#0 | PDO->__construct |
#1 | Phalcon\Db\Adapter\Pdo\AbstractPdo->connect |
#2 | Phalcon\Db\Adapter\Pdo\AbstractPdo->__construct /srv/ChatHispanoEngine/releases/94/config/services.php (46) <?php $di['config'] = $config; $di['session'] = function () use ($config) { $env = trim(file_get_contents(__DIR__.'/environment.txt')); $node = trim(file_get_contents(__DIR__.'/node.txt')); $path = $config->session->path; $manager = new \Phalcon\Session\Manager(); $serializer = new \Phalcon\Storage\SerializerFactory(); $factory = new \Phalcon\Storage\AdapterFactory($serializer); $o = new \Phalcon\Session\Adapter\Redis($factory, array( 'host' => '127.0.0.1', 'port' => 6379, 'uniqueId' => $config->session->name, )); $manager->setAdapter($o); $manager->start(); return $manager; }; $di['flash'] = function () { return new \Phalcon\Flash\Direct(array( 'error' => 'alert alert-danger alert-dismissible fade show', 'success' => 'alert alert-success alert-dismissible fade show', 'notice' => 'alert alert-info alert-dismissible fade show', 'warning' => 'alert alert-warning alert-dismissible fade show', )); }; $di['flashSession'] = function () { return new \ChatHispanoEngine\Core\Library\Flash(); }; $di['security'] = function () { $o = new \Phalcon\Encryption\Security(); $o->setWorkFactor(12); return $o; }; $di['db'] = function () use ($config) { $node = trim(file_get_contents(__DIR__.'/node.txt')); $conf = $config->database->toArray(); $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array( 'host' => $conf[$node]['host'], 'username' => $conf[$node]['username'], 'password' => $conf[$node]['password'], 'dbname' => $conf[$node]['dbname'], 'options' => array( \PDO::ATTR_CASE => \PDO::CASE_LOWER, ), 'persistent' => true, )); $connection->execute('SET NAMES '.$conf[$node]['charset']); return $connection; }; $di['url'] = function () { return new \Phalcon\Mvc\Url(); }; $di['voltService'] = function ($view) use ($config) { $di = $this; $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di); $cache_dir = $config->view->cache->dir; if (!is_dir($cache_dir)) { mkdir($cache_dir, 0777, true); } $env = trim(file_get_contents(__DIR__.'/environment.txt')); $volt->setOptions(array( 'path' => $cache_dir, 'extension' => '.compiled', 'always' => $env == 'prod' ? false : true, )); $compiler = $volt->getCompiler(); $compiler->addFunction('assets', function ($resolvedArgs, $exprArgs) use ($di) { return $di->get('assets'); }); $compiler->addFunction('_t', function ($resolvedArgs, $exprArgs) use ($di) { return '$this->translate->translate('.$resolvedArgs.')'; }); $compiler->addFunction('flashSession', function ($resolvedArgs, $exprArgs) use ($di) { return '$this->flashSession->output()'; }); $compiler->addFunction('rand', function ($resolvedArgs, $exprArgs) use ($di) { return 'rand('.$resolvedArgs.')'; }); $compiler->addFunction('isset', 'isset'); $compiler->addFilter('round', function ($resolvedArgs, $exprArgs) { return 'round('.$resolvedArgs.', PHP_ROUND_HALF_DOWN)'; }); $compiler->addFilter('urlencode', function ($resolvedArgs, $exprArgs) { return 'urlencode('.$resolvedArgs.')'; }); $compiler->addFilter('rawurlencode', function ($resolvedArgs, $exprArgs) { return 'rawurlencode('.$resolvedArgs.')'; }); $compiler->addFilter('urldecode', function ($resolvedArgs, $exprArgs) { return 'urldecode('.$resolvedArgs.')'; }); $compiler->addFilter('utf8encode', function ($resolvedArgs, $exprArgs) { return 'utf8_encode('.$resolvedArgs.')'; }); $compiler->addFilter('utf8decode', function ($resolvedArgs, $exprArgs) { return 'utf8_decode('.$resolvedArgs.')'; }); $compiler->addFilter('escapetahead', function ($resolvedArgs, $exprArgs) { return 'str_replace(["\'","à","á","è","é","í","ò","ó","ú"], ["'","à","á","è","é","í","ò","ó","ú"], '.$resolvedArgs.')'; }); $compiler->addFunction('isArray', function ($resolvedArgs, $exprArgs) { return 'is_array('.$resolvedArgs.')'; }); $compiler->addFunction('in_array', function ($resolvedArgs, $exprArgs) { return 'in_array('.$resolvedArgs.')'; }); $compiler->addFunction('implode', function ($resolvedArgs, $exprArgs) { return 'implode('.$resolvedArgs.')'; }); $compiler->addFunction('date', function ($resolvedArgs, $exprArgs) { return 'date('.$resolvedArgs.')'; }); $compiler->addFunction('max', function ($resolvedArgs, $exprArgs) { return 'max('.$resolvedArgs.')'; }); $compiler->addFunction('min', function ($resolvedArgs, $exprArgs) { return 'min('.$resolvedArgs.')'; }); $compiler->addFunction('htmlspecialchars', function ($resolvedArgs, $exprArgs) { return 'htmlspecialchars('.$resolvedArgs.')'; }); return $volt; }; $di['auth'] = function () { return new \ChatHispanoEngine\Core\Auth\Auth(); }; $di['mail'] = function () use ($di) { return new \ChatHispanoEngine\Core\Library\Mail( $di['redis_cluster'] ); }; $di['acl'] = function () { return new \Phalcon\UserPlugin\Acl\Acl(); }; $di['cache'] = function () use ($di, $config) { return new \Phalcon\Cache\Adapter\Redis(new \Phalcon\Storage\SerializerFactory(), array( 'host' => '127.0.0.1', 'port' => 6379, 'prefix' => $config->session->name.'::', )); }; $di['modelsCache'] = function () use ($di, $config) { $serializerFactory = new \Phalcon\Storage\SerializerFactory(); $adapterFactory = new \Phalcon\Cache\AdapterFactory($serializerFactory); $options = [ 'defaultSerializer' => 'Php', 'lifetime' => 7200 ]; $adapter = $adapterFactory->newInstance('apcu', $options); return new \Phalcon\Cache\Cache($adapter); }; $di['viewCache'] = $di['cache']; $di['model_manager'] = function () { return new \Phalcon\Mvc\Model\Manager(); }; $di['translate'] = function () use ($di, $config) { $available = $config->i18n->available_languages->toArray(); $default = $config->i18n->default_locale; $language = null; if (php_sapi_name() != 'cli') { $language = $di['session']->get('lang'); } if (null === $language || false === $language || $language == '') { /** * We try to get the language from http request * They are sort from highest priority to low priority * so the first one we support is the one we will use. * If none is found, the default is taken. */ $found = false; if (php_sapi_name() != 'cli') { $request = new \Phalcon\Http\Request(); $langs = $request->getLanguages(); foreach ($langs as $l) { if (isset($available[$l['language']])) { $language = $available[$l['language']]; $found = true; break; } } } if (false === $found) { $language = $default; } } if (!file_exists(__DIR__.'/../I18N/'.$language)) { $language = $default; } return new \iwalkalone\Translator($available, $language, __DIR__.'/../I18N/', $language, [ 'creg', 'chan', 'nick', 'admin', 'oper', 'memo', 'clones', 'ipvirtual', 'docking', 'datacenter', 'proxyscanner', 'garbagecollector', 'wormhunter', 'ayuda', 'errmsg', 'web', 'login', 'shorten', 'foro', 'date', 'bugslayer', ]); }; $di['logger'] = function () { return new \iwalkalone\Logger(); }; $di['oauth2_storage'] = function () { return new \ChatHispanoEngine\Core\Library\OAuth2\EmailStorage(); }; $di['assets'] = function () { return new \Phalcon\Assets\Manager(new \Phalcon\Html\TagFactory(new \Phalcon\Html\Escaper())); }; include 'managers.php'; |
#3 | Application->{closure} |
#4 | Phalcon\Di\Service->resolve |
#5 | Phalcon\Di\Di->get |
#6 | Phalcon\Di\Di->getShared |
#7 | Phalcon\Mvc\Model\Manager->getConnection |
#8 | Phalcon\Mvc\Model\Manager->getReadConnection |
#9 | Phalcon\Mvc\Model->getReadConnection |
#10 | Phalcon\Mvc\Model\Query->getReadConnection |
#11 | Phalcon\Mvc\Model\Query->executeSelect |
#12 | Phalcon\Mvc\Model\Query->execute |
#13 | Phalcon\Mvc\Model::find /srv/ChatHispanoEngine/releases/94/apps/Core/Managers/InspIRCd/ChannelManager.php (4139) <?php namespace ChatHispanoEngine\Core\Managers\InspIRCd; use ChatHispanoEngine\Core\Library\Cdn\DefaultCdn as Cdn; use ChatHispanoEngine\Core\Library\Graphics; use ChatHispanoEngine\Core\Models\User; use ChatHispanoEngine\Core\Models\Channel\Datasheet; use ChatHispanoEngine\Core\Models\Channel\Override; use ChatHispanoEngine\Core\Models\InspIRCd\Channel; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\History; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Forbid; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Section; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Access; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Hit; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Exception as AkickException; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Exception\Hit as ExceptionHit; use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Status; use ChatHispanoEngine\Core\Models\InspIRCd\Nick\History as NickHistory; use ChatHispanoEngine\Core\Exception\Exception; use ChatHispanoEngine\Core\Exception\ErrorCodes; use Phalcon\Mvc\Model\Transaction\Manager as PhalconTxManager; class ChannelManager extends \Phalcon\Mvc\Model\Manager { public const PAGE_SIZE = 20; public const CHANNEL_WARN_EXPIRE_DAYS = 21; public const CHANNEL_EXPIRE_DAYS = 30; public const REDIS_HASH_CHANNEL_IDENTIFY = 'chathispano_hash_channel_identify'; public const SUCCESSOR_LEVEL = 499; public const CHANNEL_MODES = [ 'C' => ['params' => ['on' => 0, 'off' => 0], ], 'd' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ], 'E' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^[\*~]{0,1}\d+:\d+(:\d+(:\d+)?)?$/'], ], 'F' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ], 'f' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\*{0,1}\d+:\d+$/'], ], 'H' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+[yMmdh]{0,1}$/'], ], 'i' => ['params' => ['on' => 0, 'off' => 0], ], 'J' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ], 'j' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ], 'K' => ['params' => ['on' => 0, 'off' => 0], ], 'k' => ['params' => ['on' => 1, 'off' => 1], ], 'l' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ], 'M' => ['params' => ['on' => 0, 'off' => 0], ], 'm' => ['params' => ['on' => 0, 'off' => 0], ], 'N' => ['params' => ['on' => 0, 'off' => 0], ], 'n' => ['params' => ['on' => 0, 'off' => 0], ], 'O' => ['params' => ['on' => 0, 'off' => 0], ], 'p' => ['params' => ['on' => 0, 'off' => 0], ], 'Q' => ['params' => ['on' => 0, 'off' => 0], ], 'R' => ['params' => ['on' => 0, 'off' => 0], ], 'r' => ['params' => ['on' => 0, 'off' => 0], ], 'S' => ['params' => ['on' => 0, 'off' => 0], ], 's' => ['params' => ['on' => 0, 'off' => 0], ], 'T' => ['params' => ['on' => 0, 'off' => 0], ], 't' => ['params' => ['on' => 0, 'off' => 0], ], 'u' => ['params' => ['on' => 0, 'off' => 0], ], 'W' => ['params' => ['on' => 0, 'off' => 0], ], 'x' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^[\*~]{0,1}\d+:\d+$/'], ], 'y' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ], 'z' => ['params' => ['on' => 0, 'off' => 0], ], ]; protected $channel_public_columns = 'name,founder,successor,section,description,is_suspended,suspend_ts,suspend_duration,suspend_reason,time_registered,last_topic,last_topic_by,last_topic_time'; protected $default_levels = [ 'AUTOOP' => 300, 'AUTOVOICE' => 100, 'AUTODEOP' => 200, 'AUTODEVOICE' => 50, 'NOJOIN' => -1, 'INVITE' => 300, 'AKICK-CHANGE' => 500, 'AKICK-LIST' => 300, 'SET' => 500, 'CLEAR' => 500, 'TOPIC' => 500, 'UNBAN' => 300, 'OPDEOP' => 100, 'VOICEDEVOICE' => 100, 'ACC-LIST' => 0, 'ACC-CHANGE' => 500, 'MEMO-RECV' => 500, 'MEMO-SEND' => 0, 'BLOGGER' => 500, 'FORUM' => 500, 'IDENTIFY' => 0, ]; public function getDefaultLevels() { return $this->default_levels; } public function listSections($limit = 0) { if ($limit > 0) { return Section::find([ 'order' => 'section_order ASC, code ASC', 'limit' => $limit, ]); } else { return Section::find([ 'order' => 'section_order ASC, code ASC', ]); } } public function getSection($code) { $o = Section::findFirst([ 'code = :code:', 'bind' => [ 'code' => mb_strtoupper($code), ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_NOT_FOUND); } return $o; } public function getSectionBySlug($slug) { $o = Section::findFirst([ 'slug = :slug:', 'bind' => [ 'slug' => mb_strtolower($slug), ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_NOT_FOUND); } return $o; } protected function checkSectionParameters(array $data) { if (!isset($data['name']) || strlen($data['name']) == "") { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'messages' => ['Name cannot be empty'], ]); } if (!isset($data['description']) || strlen($data['description']) < 10) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'messages' => ['Description must have 10 characters at least'], ]); } } public function newSection(array $data) { if (!isset($data['code']) || strlen($data['code']) != 3) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'messages' => ['Code must be 3 letter string'], ]); } $this->checkSectionParameters($data); $data['code'] = mb_strtoupper($data['code']); $o = new Section(); $o->assign($data); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function updateSection($code, array $data) { $o = $this->getSection($code); $this->checkSectionParameters($data); $o->assign($data); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function deleteSection($code) { $o = $this->getSection($code); if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function countListBot($pattern, $nick, $ip) { if (strlen($pattern) > 0) { $pattern = str_replace('*', '%', mb_strtolower($pattern)); return Channel::count([ 'name LIKE :pattern:', 'bind' => [ 'pattern' => $pattern, ], ]); } else { return Channel::count([ 'bind' => [ 'pattern' => $pattern, ], ]); } } public function getAll() { return Channel::find(); } public function getListBot($pattern, $page, $nick, $ip) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($nick, 'preoper'); if (strlen($pattern) > 0) { $pattern = str_replace('*', '%', mb_strtolower($pattern)); return Channel::find([ 'name LIKE :pattern:', 'bind' => [ 'pattern' => $pattern, ], 'order' => 'name ASC', 'limit' => self::PAGE_SIZE, 'offset' => ($page - 1) * self::PAGE_SIZE, ]); } else { return Channel::find([ 'order' => 'name ASC', 'limit' => self::PAGE_SIZE, 'offset' => ($page - 1) * self::PAGE_SIZE, ]); } } public function countListGI() { return Channel::count([ 'ig = 1', 'order' => 'name ASC', ]); } public function getListGIAll() { return Channel::find([ 'ig = 1', 'order' => 'name ASC', ]); } public function getListGI($page, $nick) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($nick, 'preoper'); return Channel::find([ 'ig = 1', 'order' => 'name ASC', 'limit' => self::PAGE_SIZE, 'offset' => ($page - 1) * self::PAGE_SIZE, ]); } public function count() { return Channel::count(); } public function countByUrl($url) { return Channel::count([ 'ig = :ig: AND (LOWER(description) like :url: or LOWER(entrymsg) like :url: or LOWER(last_topic) like :url:)', 'bind' => [ 'ig' => 1, 'url' => '%'.mb_strtolower($url).'%', ] ]); } public function listAll() { return Channel::find(); } public function listIg() { return Channel::find([ 'ig = :ig:', 'bind' => [ 'ig' => 1, ], ]); } public function listSuspendExpired() { return Channel::find([ 'is_suspended = 1 AND suspend_ts + suspend_duration <= :ts:', 'bind' => [ 'ts' => time(), ], ]); } public function getList($name, $order = 'name ASC', $from = 0, $num = 100, $full = false) { if ($full) { $columns = '*'; } else { $columns = $this->channel_public_columns; } if (strlen($name) > 0) { $conditions = 'LOWER(name) LIKE :name:'; $bind = [ 'name' => '%'.mb_strtolower($name).'%', ]; } else { $conditions = ''; $bind = []; } if ($conditions == '') { return Channel::find(array( 'columns' => $columns, 'order' => $order, 'limit' => $num, 'offset' => $from, )); } else { return Channel::find(array( $conditions, 'bind' => $bind, 'columns' => $columns, 'order' => $order, 'limit' => $num, 'offset' => $from, )); } } public function getImportant() { $config = $this->getDI()->get('config'); $redis = $this->getDI()->get('redis_cluster'); $list = $redis->hGetAll('chathispano_channels_hash_name'); $data = []; foreach ($list as $item) { $o = json_decode($item, true); $cnt = $o['cnt_members']; if ($cnt < $config->channels->important->minimum_nicks) { continue; } if (preg_match('/[sp]/', $o['modes'])) { continue; } if (!isset($data[$cnt])) { $data[$cnt] = []; } $data[$cnt][] = [ 'name' => $o['name'], 'description' => $o['topic'], 'users' => $o['cnt_members'], 'important' => 0, ]; } krsort($data, SORT_NUMERIC); $result = []; foreach ($data as $cnt => $channels) { foreach ($channels as $c) { $result[] = $c; } } return $result; } public function get($name, $full = false, $cached = false) { if ($cached === true) { $o = Channel::findFirst([ 'columns' => $full ? '*' : $this->channel_public_columns, 'name = :name:', 'bind' => [ 'name' => mb_strtolower($name), ], 'cache' => [ 'key' => 'inspircd-channel-'.mb_strtolower($name).($full ? '-full' : ''), 'lifetime' => 300, ], ]); } else { $o = Channel::findFirst([ 'columns' => $full ? '*' : $this->channel_public_columns, 'name = :name:', 'bind' => [ 'name' => mb_strtolower($name), ], ]); } if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NOT_FOUND); } return $o; } protected function levelExists($level) { return isset($this->default_levels[mb_strtoupper($level)]); } public function normalizeLevels(array $data) { foreach ($data as $key => $value) { if (!isset($this->default_levels[$key])) { unset($data[$key]); } } $data = array_merge($this->default_levels, $data); return $data; } public function checkName($name) { return preg_match("/^#[A-Za-z0-9áàéèíòóúñç_\.^\\\\\/#%&@=-]{1,29}$/", $name); } protected function checkChannel($name) { $o = null; try { $o = $this->get($name, true); } catch (\Exception $e) { } if ($o) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_REGISTERED); } if (!$this->checkName($name)) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_INVALID); } } public function countHistory($channel, $nick, $type = 'DEFAULT') { $manager = $this->getDI()->get('inspircd_nick_manager'); $manager->checkOperator($nick, 'preoper'); switch ($type) { case 'ALL': return History::count([ [ 'channel' => mb_strtolower($channel), ], ]); break; case 'ACCESS': return History::count([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(REGA|REGS|REGD|REGE|DELA)$'), ], ]); break; case 'AKICKS': return History::count([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(AKA|AKS|AKD|AKE)$'), ], ]); break; case 'TOPICS': return History::count([ [ 'channel' => mb_strtolower($channel), 'event' => 'ST', ], ]); break; default: return History::count([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(?!(REGA|REGS|REGD|REGE|DELA|AKA|AKS|AKD|AKE|ST))[A-Z]+$'), ], ]); break; } } public function getHistory($channel, $nick, $page = 1, $type = 'DEFAULT') { $manager = $this->getDI()->get('inspircd_nick_manager'); $manager->checkOperator($nick, 'preoper'); switch ($type) { case 'ALL': return History::find([ [ 'channel' => mb_strtolower($channel), ], 'sort' => [ 'date' => -1, ], 'limit' => self::PAGE_SIZE, 'skip' => self::PAGE_SIZE * ($page - 1), ]); break; case 'ACCESS': return History::find([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(REGA|REGS|REGD|REGE|DELA)$'), ], 'sort' => [ 'date' => -1, ], 'limit' => self::PAGE_SIZE, 'skip' => self::PAGE_SIZE * ($page - 1), ]); break; case 'AKICKS': return History::find([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(AKA|AKD|AKE)$'), ], 'sort' => [ 'date' => -1, ], 'limit' => self::PAGE_SIZE, 'skip' => self::PAGE_SIZE * ($page - 1), ]); break; case 'TOPICS': return History::find([ [ 'channel' => mb_strtolower($channel), 'event' => 'ST', ], 'sort' => [ 'date' => -1, ], 'limit' => self::PAGE_SIZE, 'skip' => self::PAGE_SIZE * ($page - 1), ]); break; default: return History::find([ [ 'channel' => mb_strtolower($channel), 'event' => new \MongoDB\BSON\Regex('^(?!(REGA|REGS|REGD|REGE|DELA|AKA|AKD|AKE|ST))[A-Z]+$'), ], 'sort' => [ 'date' => -1, ], 'limit' => self::PAGE_SIZE, 'skip' => self::PAGE_SIZE * ($page - 1), ]); break; } } public function getHistoryAll($channel) { return History::find([ [ 'channel' => mb_strtolower($channel), ], 'sort' => [ 'date' => -1, ], ]); } public function createHistory($channel, $event, $ip, array $parameters) { $o = new History(); $o->date = new \MongoDB\BSON\UTCDateTime(round(microtime(true) * 1000)); $o->channel = mb_strtolower($channel); $o->event = $event; $o->ip = $ip; $o->parameters = $parameters; if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } protected function create(array $data, $ip) { $this->checkChannel($data['name']); $defaults = [ 'successor' => new \Phalcon\Db\RawValue("NULL"), 'section' => new \Phalcon\Db\RawValue("NULL"), 'url' => new \Phalcon\Db\RawValue("NULL"), 'email' => new \Phalcon\Db\RawValue("NULL"), 'levels' => json_encode($this->normalizeLevels([])), 'mlock' => '+', 'is_suspended' => 0, 'suspend_by' => new \Phalcon\Db\RawValue("NULL"), 'suspend_ts' => new \Phalcon\Db\RawValue("NULL"), 'suspend_duration' => new \Phalcon\Db\RawValue("NULL"), 'suspend_reason' => new \Phalcon\Db\RawValue("NULL"), 'time_registered' => time(), 'time_last_use' => time(), 'last_modes' => '', 'last_topic' => new \Phalcon\Db\RawValue("NULL"), 'last_topic_by' => new \Phalcon\Db\RawValue("NULL"), 'last_topic_time' => new \Phalcon\Db\RawValue("NULL"), ]; $data = array_merge($defaults, $data); $data['founder'] = mb_strtolower($data['founder']); $data['password'] = $this->getDI()->get('security')->hash($data['password']); $o = new Channel(); $o->assign($data); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->setStatus($data['name'], Status::STATUS_REGISTERED, $ip, $data['founder']); return $o; } protected function checkFounder($founder) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $o = $nick_manager->get($founder, true); if ($o->getTimeRegistered() > time() - 7 * 24 * 3600) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_WAIT); } return $o; } public function new(array $data, $oper, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel'); $o = $this->create(array_merge($data, [ 'founder' => $oper, ]), $ip); $this->createHistory($data['name'], History::EVENT_REGISTER, $ip, [ 'who' => $oper, ]); $dbTx->commit(); return $o; } public function registerRequest(array $data, $ip) { $dbTx = (new PhalconTxManager())->get(); $this->checkChannel($data['name']); $n = $this->checkFounder($data['founder']); $o = $this->getStatus($data['name']); if ($o) { switch ($o->status) { case Status::STATUS_DENIED: throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_DENIED); break; case Status::STATUS_REJECTED: throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_REJECTED); break; case Status::STATUS_DROPPED: throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_DROPPED); break; case Status::STATUS_REQUESTED: if ($o->nick == mb_strtolower($data['founder'])) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_REQUESTED); } else { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_IN_PROCESS); } break; default: break; } } else { $cnt = Status::count([ [ 'status' => (int)Status::STATUS_REQUESTED, 'nick' => mb_strtolower($data['founder']), ], ]); if ($cnt > 0) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_WAIT); } } $this->setStatus($data['name'], Status::STATUS_REQUESTED, $ip, $data['founder'], '', $data['password'], $data['description'], $n->getEmail()); $this->createHistory($data['name'], History::EVENT_REQUEST, $ip, [ 'who' => $data['founder'], ]); $dbTx->commit(); } public function registerAccept($name, $oper, $section, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel', 'canregister'); $status = $this->getStatus($name); if (!$status || $status->status != Status::STATUS_REQUESTED) { if ($status && ($status->status == Status::STATUS_REJECTED || $status->status == Status::STATUS_DENIED) && $status->founder) { try { $nick_manager->checkOperator($oper, 'devel'); } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED); } } else { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED); } } $this->checkChannel($status->channel); $f = $this->checkFounder($status->founder); $o = $this->create([ 'name' => $status->channel, 'section' => mb_strtoupper($section), 'founder' => $status->founder, 'password' => $status->password, 'description' => $status->description, ], $ip); $this->createHistory($status->channel, History::EVENT_ACCEPT, $ip, [ 'who' => $oper, ]); $this->createHistory($status->channel, History::EVENT_REGISTER, $ip, [ 'who' => $status->founder, ]); $dbTx->commit(); $o = $this->get($name, true); $this->enqueue($o); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $n = $irc_manager->getNick($status->founder); if ($n) { $msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been approved.', [ 'name' => $status->channel ], 'creg'); $irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg); } $mailer = $this->getDI()->get('mail'); $mailer->addTo($f->getEmail()); $mailer->setLanguage('es'); $mailer->send( 'Chat Hispano', '[ChatHispano] El registro del canal canal '.$status->channel.' ha sido aceptado', 'creg_accept', null, [ 'nick' => $f->getNick(), 'channel' => $status->channel, 'images' => [ 'logo' => 'public/assets/backoffice/img/logo-medium.jpg', ], ] ); return $o; } public function registerCancel($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $status = $this->getStatus($name); if (!$status || $status->status != Status::STATUS_REQUESTED) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED); } if (mb_strtolower($nick) != $status->nick) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } $this->setStatus($status->channel, Status::STATUS_NOT_REGISTERED, $ip, $status->nick); $dbTx->commit(); $this->createHistory($name, History::EVENT_CANCEL, $ip, [ 'who' => $nick, ]); } public function registerDeny($name, $oper, $ip, $reason) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel', 'canregister'); $status = $this->getStatus($name); if (!$status || $status->status != Status::STATUS_REQUESTED) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED); } $this->setStatus($status->channel, Status::STATUS_DENIED, $ip, $status->nick, $reason, $status->password, $status->description, $status->email); $this->createHistory($name, History::EVENT_DENY, $ip, [ 'who' => $oper, 'reason' => $reason, ]); $dbTx->commit(); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $n = $irc_manager->getNick($status->nick); if ($n) { $msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been denied:', [ 'name' => $status->channel ], 'creg'); $irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg); $irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $reason); } $f = $this->checkFounder($status->nick); $mailer = $this->getDI()->get('mail'); $mailer->addTo($f->getEmail()); $mailer->setLanguage('es'); $mailer->send( 'Chat Hispano', '[ChatHispano] El registro del canal canal '.$status->channel.' ha sido denegado', 'creg_denied', null, [ 'nick' => $f->getNick(), 'channel' => $status->channel, 'reason' => $reason, 'images' => [ 'logo' => 'public/assets/backoffice/img/logo-medium.jpg', ], ] ); } public function registerReject($name, $oper, $ip, $reason) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel', 'canregister'); $status = $this->getStatus($name); if (!$status || $status->status != Status::STATUS_REQUESTED) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED); } $this->setStatus($status->channel, Status::STATUS_REJECTED, $ip, $status->nick, $reason, $status->password, $status->description, $status->email); $this->createHistory($name, History::EVENT_REJECT, $ip, [ 'who' => $oper, 'reason' => $reason, ]); $dbTx->commit(); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $n = $irc_manager->getNick($status->nick); if ($n) { $msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been rejected:', [ 'name' => $status->channel ], 'creg'); $irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg); $irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $reason); } $f = $this->checkFounder($status->nick); $mailer = $this->getDI()->get('mail'); $mailer->addTo($f->getEmail()); $mailer->setLanguage('es'); $mailer->send( 'Chat Hispano', '[ChatHispano] El registro del canal canal '.$status->channel.' ha sido rechazado', 'creg_reject', null, [ 'nick' => $f->getNick(), 'channel' => $status->channel, 'reason' => $reason, 'images' => [ 'logo' => 'public/assets/backoffice/img/logo-medium.jpg', ], ] ); } public function registerAllow($name, $oper, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'preoper'); $status = $this->getStatus($name); if (!$status || ($status && $status->status != Status::STATUS_DROPPED && $status->status != Status::STATUS_REJECTED && $status->status != Status::STATUS_DENIED)) { throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_DENIED); } $this->setStatus($status->channel, Status::STATUS_NOT_REGISTERED, $ip, $status->nick); $this->createHistory($name, History::EVENT_PERMIT, $ip, [ 'who' => $oper, ]); $dbTx->commit(); } protected function update(Channel $o, array $data) { $o->assign($data); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function suspend($name, $oper, $reason, $duration, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $operator = $nick_manager->checkOperator($oper, 'preoper', ''); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ALREADY_SUSPENDED); } $seconds = new \Khill\Duration\Duration(str_replace('+', '', $duration)); if (!$operator->isAdmin() && $seconds->toSeconds() > 10 * 24 * 3600) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPEND_TOO_MUCH_TIME); } if ($seconds->toSeconds() < 3600) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPEND_TOO_SHORT); } $o = $this->update($o, [ 'is_suspended' => 1, 'suspend_by' => mb_strtolower($oper), 'suspend_ts' => time(), 'suspend_duration' => $seconds->toSeconds(), 'suspend_reason' => $reason, ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->setStatus($name, Status::STATUS_SUSPENDED, $ip, $oper, $reason); $this->createHistory($name, History::EVENT_SUSPEND, $ip, [ 'who' => $oper, 'reason' => $reason, ]); $dbTx->commit(); return $o; } public function unsuspend($name, $oper, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'preoper'); $o = $this->get($name, true); if ($o->getIsSuspended() != 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NOT_SUSPENDED); } $o = $this->update($o, [ 'is_suspended' => 0, 'suspend_by' => new \Phalcon\Db\RawValue("NULL"), 'suspend_ts' => new \Phalcon\Db\RawValue("NULL"), 'suspend_duration' => new \Phalcon\Db\RawValue("NULL"), 'suspend_reason' => new \Phalcon\Db\RawValue("NULL"), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->setStatus($name, Status::STATUS_REGISTERED, $ip, $oper); $this->createHistory($name, History::EVENT_REHAB, $ip, [ 'who' => $oper, ]); $dbTx->commit(); return $o; } public function accessList($name, $op, $orderby = 'nick ASC') { $c = $this->get($name, true); $oper = false; if (false === $this->checkLevel($c, 'ACC-LIST', $op)) { try { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return Access::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => $orderby, ]); } public function accessCount($name, $op) { $c = $this->get($name, true); $oper = false; if (false === $this->checkLevel($c, 'ACC-LIST', $op)) { try { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return Access::count([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], ]); } public function accessAdd($name, $nick, $level, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $name = mb_strtolower($name); $nick = mb_strtolower($nick); $c = $this->get($name, true); if ($c->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $oper = false; if (false === $this->checkLevel($c, 'ACC-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } else { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { } } if ($level < -1 || $level >= 500 || $level == 0) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_BAD_LEVEL); } if ($oper === false) { $oplvl = $this->getLevel($c, $op); if ($level >= $oplvl) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => $name, 'nick' => $nick, ], ]); if ($o) { if ($oper === false) { if ($o->getLevel() >= $oplvl) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } if ($level == $o->getLevel()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_CHANGED, [ 'nick' => $nick, 'level' => $level, ]); } $o->assign([ 'level' => $level, 'set_by' => $op, 'set_on' => time(), ]); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($c->getName()); $this->createHistory($name, History::EVENT_ACCESS_SET, $ip, [ $nick, $level, $op, ]); $nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_SET, $ip, [ $name, $nick, $level, ]); } else { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $n = $nick_manager->get($nick, true); if ($n->getOptions()['nochaccess']) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NICK_HAS_NOCHACCESS, [ 'nick' => $nick, ]); } $o = new Access(); $o->assign([ 'channel' => mb_strtolower($name), 'nick' => mb_strtolower($nick), 'level' => $level, 'set_by' => $op, 'set_on' => time(), ]); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($c->getName()); $this->createHistory($name, History::EVENT_ACCESS_ADD, $ip, [ $nick, $level, $op, ]); $nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_ADD, $ip, [ $name, $nick, $level, ]); } $nick_manager->createHistory($nick, NickHistory::EVENT_ACCESS_RECV, $ip, [ $name, $level, $op, ]); $dbTx->commit(); return $o; } public function accessDel($name, $nick, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $name = mb_strtolower($name); $nick = mb_strtolower($nick); $c = $this->get($name, true); if ($c->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $oper = false; if (false === $this->checkLevel($c, 'ACC-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } else { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { } } $o = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => $name, 'nick' => $nick, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND); } else { if ($oper === false) { $oplvl = $this->getLevel($c, $op); if ($o->getLevel() >= $oplvl) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } } $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($c->getName()); $this->createHistory($name, History::EVENT_ACCESS_DEL, $ip, [ $nick, $op, ]); $nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_DEL, $ip, [ $name, $nick, ]); $nick_manager->createHistory($nick, NickHistory::EVENT_ACCESS_TAKEN, $ip, [ $name, $op, ]); $dbTx->commit(); return $o; } public function accessClear($name, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $name = mb_strtolower($name); $c = $this->get($name, true); if ($c->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $oper = false; if (mb_strtolower($op) != $c->getFounder() && mb_strtolower($op) != $c->getSuccessor()) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } else { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { } } $list = $c->getAccess(); foreach ($list as $o) { if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory($name, History::EVENT_ACCESS_DEL, $ip, [ $o->getNick(), $op, ]); $nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_DEL, $ip, [ $name, $o->getNick(), ]); $nick_manager->createHistory($o->getNick(), NickHistory::EVENT_ACCESS_TAKEN, $ip, [ $name, $op, ]); } $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($c->getName()); $dbTx->commit(); return $c; } public function accessHit($name, $nick, $ts = 0) { $name = mb_strtolower($name); $nick = mb_strtolower($nick); $o = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => $name, 'nick' => $nick, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND); } else { if ($ts == 0) { $o->setLastUse(time()); } else { $o->setLastUse($ts); } if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_UPDATE, [ 'message' => join(". ", $o->getMessages()), ]); } } return $o; } protected function checkMlock($mlock, array $parameters) { $op = 'on'; $on = false; $off = false; $modes = []; $params = 0; $ml_modes = []; $ml_params = []; for ($i = 0; $i < strlen($mlock); $i++) { $m = substr($mlock, $i, 1); if ($m == '+') { if ($on == true || $off == true) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Symbol %symbol% more than once', ['symbol' => '+']), ]; } $modes[] = '+'; $ml_modes[] = '+'; $on = true; $op = 'on'; } elseif ($m == '-') { if ($off == true) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Symbol %symbol more than once', ['symbol' => '-']), ]; } $modes[] = '-'; $ml_modes[] = '-'; $off = true; $op = 'off'; } else { if (in_array($m, $modes)) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Mode %mode% found more than once', ['mode' => $m]), ]; } if (!isset(self::CHANNEL_MODES[$m])) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Unknown mode %mode%', ['mode' => $m]), ]; } if ($m != 'r') { // we exclude +r parameter $modes[] = $m; if (self::CHANNEL_MODES[$m]['params'][$op] > 0) { if (!isset($parameters[$params])) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Missing parameter for mode %mode%', ['mode' => $m]), ]; } if (isset(self::CHANNEL_MODES[$m]['params']['pattern']) && !preg_match(self::CHANNEL_MODES[$m]['params']['pattern'], $parameters[$params])) { return [ 'status' => false, 'errmsg' => $this->getDI()->get('translate')->translate('Wrong parameter %param% for mode %mode%', [ 'mode' => $m, 'param' => $parameters[$params] ]), ]; } } $ml_modes[] = $m; if ($m != 'k') { if (self::CHANNEL_MODES[$m]['params'][$op] > 0) { $ml_params[] = $parameters[$params]; } } $params += self::CHANNEL_MODES[$m]['params'][$op]; } } } if (count($ml_params) > 0) { $mlock = join('', $ml_modes).' '.join(' ', $ml_params); } else { $mlock = join('', $ml_modes); } if (count($parameters) > 0) { $mode = join('', $modes).' '.join(' ', $parameters); } else { $mode = join('', $modes); } return [ 'status' => true, 'mlock' => $mlock, 'mode' => $mode, ]; } public function setMlock($name, $mlock, array $parameters, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $c = $this->get($name, true); if ($c->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $oper = false; if (false === $this->checkLevel($c, 'SET', $nick)) { try { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $result = $this->checkMlock($mlock, $parameters); if ($result['status'] === false) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_MLOCK_BAD_FORMAT, [ 'errmsg' => $result['errmsg'], ]); } $o = $this->update($c, [ 'mlock' => $result['mlock'], ]); $this->createHistory($name, History::EVENT_SET_MLOCK, $ip, [ 'mlock' => $result['mlock'], 'who' => $nick, ]); $dbTx->commit(); return [ 'mlock' => $result['mlock'], 'mode' => $result['mode'], 'obj' => $o, ]; } public function setPassword($name, $password, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'password' => $this->getDI()->get('security')->hash($password), ]); $this->unidentifyChannel($name); $this->createHistory($name, History::EVENT_SET_PASSWORD, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function checkPassword($name, $password) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if (!$this->getDI()->get('security')->checkHash($password, $o->getPassword())) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_BAD_PASSWORD); } return $o; } public function setFounder($name, $nick, $founder, $ip, $checkCredentials = true) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); if ($checkCredentials === true) { $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } } $f = $nick_manager->get($founder, true); if ($f->getOptions()['nochaccess']) { $a = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => mb_strtolower($name), 'nick' => mb_strtolower($founder), ], ]); if (!$a) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SET_FOUNDER_NICK_HAS_NOCHACCESS, [ 'nick' => $founder, ]); } } if (mb_strtolower($founder) == $o->getSuccessor()) { $o = $this->update($o, [ 'founder' => mb_strtolower($founder), 'successor' => new \Phalcon\Db\RawValue("NULL"), ]); } else { $o = $this->update($o, [ 'founder' => mb_strtolower($founder), ]); } $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->unidentifyChannel($name); $this->createHistory($name, History::EVENT_SET_FOUNDER, $ip, [ 'founder' => $founder, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setSuccessor($name, $nick, $successor, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $s = $nick_manager->get($successor, true); if ($s->getOptions()['nochaccess']) { $a = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => mb_strtolower($name), 'nick' => mb_strtolower($successor), ], ]); if (!$a) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SET_SUCCESSOR_NICK_HAS_NOCHACCESS, [ 'nick' => $successor, ]); } } $o = $this->update($o, [ 'successor' => mb_strtolower($successor), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_SET_SUCCESSOR, $ip, [ 'successor' => $successor, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function unsetSuccessor($name, $nick, $ip, $checkCredentials = true) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if ($checkCredentials === true) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } } if (strlen($o->getSuccessor()) <= 0) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NO_SUCCESSOR); } $o = $this->update($o, [ 'successor' => new \Phalcon\Db\RawValue("NULL"), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_UNSET_SUCCESSOR, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setSection($name, $nick, $section, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); try { $nick_manager->checkOperator($nick, 'devel', 'canregister'); } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } $section = mb_strtoupper($section); $s = $this->getSection($section); $o = $this->update($o, [ 'section' => $section, ]); $this->createHistory($name, History::EVENT_SET_SECTION, $ip, [ 'section' => $section, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setDescription($name, $nick, $description, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'devel', 'canregister'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'description' => $description, ]); $this->createHistory($name, History::EVENT_SET_DESCRIPTION, $ip, [ 'description' => $description, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setGi($name, $nick, $value, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($nick, 'devel'); $o = $this->update($o, [ 'ig' => mb_strtolower($value) == 'on' ? 1 : 0, ]); $event = $o->getIg() == 1 ? History::EVENT_SET_GENERAL_INTEREST : History::EVENT_UNSET_GENERAL_INTEREST; $this->createHistory($name, $event, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setUrl($name, $nick, $url, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'url' => $url, ]); $this->createHistory($name, History::EVENT_SET_URL, $ip, [ 'url' => $url, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function unsetUrl($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'url' => new \Phalcon\Db\RawValue("NULL"), ]); $this->createHistory($name, History::EVENT_UNSET_URL, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setEmail($name, $nick, $email, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'email' => $email, ]); $this->createHistory($name, History::EVENT_SET_EMAIL, $ip, [ 'email' => $email, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function unsetEmail($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'email' => new \Phalcon\Db\RawValue("NULL"), ]); $this->createHistory($name, History::EVENT_UNSET_EMAIL, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setEntrymsg($name, $nick, $entrymsg, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'entrymsg' => $entrymsg, ]); $this->createHistory($name, History::EVENT_SET_ENTRYMSG, $ip, [ 'entrymsg' => $entrymsg, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function unsetEntrymsg($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'entrymsg' => new \Phalcon\Db\RawValue("NULL"), ]); $this->createHistory($name, History::EVENT_UNSET_ENTRYMSG, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setOption($name, $nick, $option, $value, $ip, $check_operator = true) { $dbTx = (new PhalconTxManager())->get(); try { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, $option == 'openai' ? 'SET' : 500, $nick)) { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } else { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { } } if ($check_operator === true && in_array($option, ['noakick', 'noexpire', 'noads', 'expirewarn', 'forum', 'underage'])) { if ($oper === true) { if (in_array($option, ['noexpire', 'noads', 'expirewarn', 'forum', 'underage'])) { $nick_manager->checkOperator($nick, 'devel'); } } else { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $options = $o->getOptions(); $v = mb_strtolower($value) == 'on' ? true : false; if (isset($options[$option]) && $v === $options[$option]) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_OPTION_NOT_CHANGED); } // We only allow to activate openai option if channel is IG if ($option == 'openai' && $v === true && $o->getIg() != 1) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } $options[$option] = $v; $o = $this->update($o, [ 'options' => $options, ]); $this->createHistory($name, $options[$option] ? History::EVENT_SET_OPTION : History::EVENT_UNSET_OPTION, $ip, [ 'option' => $option, 'who' => $nick, ]); $dbTx->commit(); } catch (\Exception $e) { $dbTx->rollback(); throw new \Exception($e->getMessage(), $e->getCode()); } return $o; } public function setLastModes($name, $modes) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $o = $this->update($o, [ 'last_modes' => $modes, ]); return $o; } public function setTopic($name, $nick, $topic, $ts, $ip, $check_credentials = true) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if (true === $check_credentials) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'TOPIC', $nick)) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'last_topic' => $topic, 'last_topic_by' => mb_strtolower($nick), 'last_topic_time' => $ts, ]); $this->createHistory($name, History::EVENT_SET_TOPIC, $ip, [ 'topic' => $topic, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function setLevel($name, $nick, $level, $value, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } if (!$this->levelExists($level)) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_DOES_NOT_EXIST); } if (!is_numeric($value) || $value < -1 || $value > 500) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_OUT_OF_BOUNDS); } $levels = $this->normalizeLevels(json_decode($o->getLevels(), true)); $levels[strtoupper($level)] = $value; $levels = $this->normalizeLevels($levels); $o = $this->update($o, [ 'levels' => json_encode($levels), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_SET_LEVEL, $ip, [ 'level' => strtoupper($level), 'value' => $value, 'who' => $nick, ]); $dbTx->commit(); return $o; } public function disableLevel($name, $nick, $level, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } if (!$this->levelExists($level)) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_DOES_NOT_EXIST); } $levels = $this->normalizeLevels(json_decode($o->getLevels(), true)); $levels[strtoupper($level)] = 'DIS'; $levels = $this->normalizeLevels($levels); $o = $this->update($o, [ 'levels' => json_encode($levels), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_DISABLE_LEVEL, $ip, [ 'level' => strtoupper($level), 'who' => $nick, ]); $dbTx->commit(); return $o; } public function resetLevels($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 500, $nick)) { try { $nick_manager->checkOperator($nick, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = $this->update($o, [ 'levels' => json_encode($this->default_levels), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_RESET_LEVELS, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function updateLastUse($channel) { $o = $this->get($channel, true); $o = $this->update($o, [ 'time_last_use' => time(), ]); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } try { $o = $this->setOption($o->getName(), 'ChatHispano', 'expirewarn', 'off', '127.0.0.1', false); } catch (\Exception $e) { } return $o; } protected function checkAkickMask($mask, $exception = false, $oper = false) { $restrictedPrefixes = [ "U:", "G:", "X:", ]; if (false === $oper && in_array(substr($mask, 0, 2), $restrictedPrefixes)) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } // only nick, we add !*@* to the end if (preg_match("/^[^\s:!@]+$/", $mask)) { $mask .= '!*@*'; } $patterns = [ "/^r:[^\\s]+$/", // realname "/^a:[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+\\+[^\\s]+$/", // mask+realname "/^G:([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // geolocation "/^G:([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // geolocation with continent "/^g:([a-z]:)?[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+\\+([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // mask + geolocation "/^U:[a-z0-9]{16}$/", // unique user id (android) "/^U:[a-z0-9]{32}$/", // unique user id (webchat) "/^X:[a-z0-9]{16}!([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // unique user id (android) + geolocation "/^X:[a-z0-9]{32}!([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // unique user id (webchat) + geolocation "/^([a-z]:)?[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+$/", // rest of ]; $valid = false; foreach ($patterns as $p) { if (preg_match($p, $mask)) { $valid = true; break; } } if ($valid === false) { throw new Exception(null, $exception ? ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_CREATE : ErrorCodes::ERR_CHANNEL_AKICK_CREATE, [ 'message' => 'Invalid mask', ]); } // Convert to lowercase nick part in regular masks + a:, g: extbans if (substr($mask, 1, 1) != ':' || substr($mask, 0, 2) == 'a:' || substr($mask, 0, 2) == 'g:') { $parts = explode('!', $mask); $mask = strtolower($parts[0]).'!'.join('!', array_slice($parts, 1)); } return $mask; } public function akickAdd($channel, $mask, $reason, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } else { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { } } if ($oper === false) { $redis = $this->getDI()->get('redis_cluster'); $v = $redis->get('chathispano_inspircd_akick_delete_'.str_replace('#', '', $channel).'_'.$mask); if ($v && $v == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_WAIT); } } $mask = $this->checkAkickMask($mask, false, $oper); $o = new Akick(); $o->assign([ 'channel' => mb_strtolower($channel), 'mask' => $mask, 'reason' => $reason, 'author' => mb_strtolower($op), 'created_on' => new \Phalcon\Db\RawValue("NOW()"), 'last_hit' => new \Phalcon\Db\RawValue("NULL"), 'hits' => 0, ]); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_ADD, $ip, [ $mask, mb_strtolower($op), $reason, ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_ADD, $ip, [ mb_strtolower($channel), $mask, $reason, ]); $dbTx->commit(); return $o; } public function akickSet($channel, $mask, $reason, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = Akick::findFirst([ 'channel = :channel: AND mask = :mask:', 'bind' => [ 'channel' => mb_strtolower($channel), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND); } $o->assign([ 'reason' => $reason, 'author' => mb_strtolower($op), ]); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_SET, $ip, [ $mask, mb_strtolower($op), $reason, ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_SET, $ip, [ mb_strtolower($channel), $mask, $reason, ]); $dbTx->commit(); return $o; } public function akickDel($name, $mask, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = Akick::findFirst([ 'channel = :channel: AND mask = :mask:', 'bind' => [ 'channel' => mb_strtolower($name), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND); } if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } $redis = $this->getDI()->get('redis_cluster'); $redis->set('chathispano_inspircd_akick_delete_'.str_replace('#', '', $name).'_'.$mask, 1, 3600 * 24); $this->createHistory(mb_strtolower($name), History::EVENT_AKICK_DEL, $ip, [ $mask, mb_strtolower($op), ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_DEL, $ip, [ mb_strtolower($name), $mask, ]); $dbTx->commit(); return $o; } public function akickClear($name, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper', '', true); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $list = $o->getAkick(); $masks = []; foreach ($list as $a) { $masks[] = $a->getMask(); if (false === $a->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_DELETE, [ 'message' => join('. ', $a->getMessages()), ]); } } foreach ($masks as $mask) { $redis = $this->getDI()->get('redis_cluster'); $redis->set('chathispano_inspircd_akick_delete_'.str_replace('#', '', $name).'_'.$mask, 1, 3600 * 24); $this->createHistory(mb_strtolower($name), History::EVENT_AKICK_DEL, $ip, [ $mask, mb_strtolower($op), ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_DEL, $ip, [ mb_strtolower($name), $mask, ]); } $dbTx->commit(); return $o; } public function akickList($name, $op, $ip, $order = 'mask ASC') { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return Akick::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => $order, ]); } public function akickEnforce($name, $users, $op, $ip) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $exceptions = AkickException::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => 'hits DESC', ]); $list = Akick::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => 'hits DESC', ]); $result = []; foreach ($users as $u) { $exception = false; foreach ($exceptions as $o) { if ($nick_manager->checkMask($u, $o->getMask())) { $exception = true; break; } } if (false === $exception) { foreach ($list as $o) { if (isset($u['modes']) && preg_match("/[Bok]/", $u['modes'])) { continue; } if ($nick_manager->checkMask($u, $o->getMask())) { $result[] = array_merge($u, [ 'mask' => $o->getMask(), 'reason' => $o->getReason(), 'author' => $o->getAuthor(), ]); break; } } } } return $result; } public function akickAffectsUser(Channel $c, array $user) { if ($c->getIsSuspended() == 1) { return false; } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $list = AkickException::find([ 'channel = :channel:', 'bind' => [ 'channel' => $c->getName(), ], 'order' => 'hits DESC', ]); foreach ($list as $o) { if ($nick_manager->checkMask($user, $o->getMask())) { return false; } } $list = Akick::find([ 'channel = :channel:', 'bind' => [ 'channel' => $c->getName(), ], 'order' => 'hits DESC', ]); foreach ($list as $o) { if ($nick_manager->checkMask($user, $o->getMask())) { return true; } } return false; } public function akickCheck($name, $user, $op, $ip) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (mb_strtolower($user['nick']) != mb_strtolower($op)) { if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } } $list = AkickException::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => 'hits DESC', ]); foreach ($list as $o) { if ($nick_manager->checkMask($user, $o->getMask())) { return []; } } $list = Akick::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => 'hits DESC', ]); $result = []; foreach ($list as $o) { if ($nick_manager->checkMask($user, $o->getMask())) { $result[] = [ 'mask' => $o->getMask(), 'reason' => $o->getReason(), 'author' => $o->getAuthor(), ]; break; } } return $result; } public function akickCount($name, $op) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return Akick::count([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], ]); } public function akickHitCount($channel, $mask, $victim) { $parameters = []; if ($channel != '') { $parameters['channel'] = mb_strtolower($channel); } if ($mask != '') { $parameters['mask'] = mb_strtolower($mask); } if ($victim != '') { $parameters['victim'] = mb_strtolower($victim); } return Hit::count([ $parameters, ]); } public function akickHitList($channel, $mask, $victim, $page = 1) { $parameters = []; if ($channel != '') { $parameters['channel'] = mb_strtolower($channel); } if ($mask != '') { $parameters['mask'] = mb_strtolower($mask); } if ($victim != '') { $parameters['victim'] = mb_strtolower($victim); } return Hit::find([ $parameters, 'limit' => self::PAGE_SIZE, 'skip' => ($page - 1) * self::PAGE_SIZE, ]); } public function akickHit($name, $mask, $nick, $ts = 0) { $dbTx = (new PhalconTxManager())->get(); $o = Akick::findFirst([ 'channel = :name: AND mask = :mask:', 'bind' => [ 'name' => mb_strtolower($name), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND); } if ($ts == 0) { $o->setLastHit(new \Phalcon\Db\RawValue("NOW()")); } else { $o->setLastHit(date('Y-m-d H:i:s', $ts)); } $o->setHits($o->getHits() + 1); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [ 'message' => join(". ", $o->getMessages()), ]); } $h = new Hit(); $h->date = new \MongoDB\BSON\UTCDateTime(time() * 1000); $h->channel = $o->getChannel(); $h->mask = $mask; $h->victim = mb_strtolower($nick); $h->reason = $o->getReason(); if (false === $h->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [ 'message' => join(". ", $h->getMessages()), ]); } $dbTx->commit(); return $o; } public function akickFind() { return Akick::find(); } public function akickExceptionAdd($channel, $mask, $reason, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } else { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { } } $mask = $this->checkAkickMask($mask, true, $oper); $o = new AkickException(); $o->assign([ 'channel' => mb_strtolower($channel), 'mask' => $mask, 'reason' => $reason, 'author' => mb_strtolower($op), 'created_on' => new \Phalcon\Db\RawValue("NOW()"), 'last_hit' => new \Phalcon\Db\RawValue("NULL"), 'hits' => 0, ]); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_EXCEPTION_ADD, $ip, [ $mask, mb_strtolower($op), $reason, ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_ADD, $ip, [ mb_strtolower($channel), $mask, $reason, ]); $dbTx->commit(); return $o; } public function akickExceptionSet($channel, $mask, $reason, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = AkickException::findFirst([ 'channel = :channel: AND mask = :mask:', 'bind' => [ 'channel' => mb_strtolower($channel), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND); } $o->assign([ 'reason' => $reason, 'author' => mb_strtolower($op), ]); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_EXCEPTION_SET, $ip, [ $mask, mb_strtolower($op), $reason, ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_SET, $ip, [ mb_strtolower($channel), $mask, $reason, ]); $dbTx->commit(); return $o; } public function akickExceptionDel($name, $mask, $op, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } $o = AkickException::findFirst([ 'channel = :channel: AND mask = :mask:', 'bind' => [ 'channel' => mb_strtolower($name), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND); } if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->createHistory(mb_strtolower($name), History::EVENT_AKICK_EXCEPTION_DEL, $ip, [ $mask, mb_strtolower($op), ]); $nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_DEL, $ip, [ mb_strtolower($name), $mask, ]); $dbTx->commit(); return $o; } public function akickExceptionList($name, $op, $ip, $order = 'mask ASC') { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return AkickException::find([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], 'order' => $order, ]); } public function akickExceptionCount($name, $op) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $oper = false; if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) { try { $nick_manager->checkOperator($op, 'preoper'); $oper = true; } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } return AkickException::count([ 'channel = :channel:', 'bind' => [ 'channel' => mb_strtolower($name), ], ]); } public function akickExceptionHitCount($channel, $mask, $victim) { $parameters = []; if ($channel != '') { $parameters['channel'] = mb_strtolower($channel); } if ($mask != '') { $parameters['mask'] = mb_strtolower($mask); } if ($victim != '') { $parameters['victim'] = mb_strtolower($victim); } return ExceptionHit::count([ $parameters, ]); } public function akickExceptionHitList($channel, $mask, $victim, $page = 1) { $parameters = []; if ($channel != '') { $parameters['channel'] = mb_strtolower($channel); } if ($mask != '') { $parameters['mask'] = mb_strtolower($mask); } if ($victim != '') { $parameters['victim'] = mb_strtolower($victim); } return ExceptionHit::find([ $parameters, 'limit' => self::PAGE_SIZE, 'skip' => ($page - 1) * self::PAGE_SIZE, ]); } public function akickExceptionHit($name, $mask, $nick, $ts = 0) { $dbTx = (new PhalconTxManager())->get(); $o = AkickException::findFirst([ 'channel = :name: AND mask = :mask:', 'bind' => [ 'name' => mb_strtolower($name), 'mask' => $mask, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND); } if ($ts == 0) { $o->setLastHit(new \Phalcon\Db\RawValue("NOW()")); } else { $o->setLastHit(date('Y-m-d H:i:s', $ts)); } $o->setHits($o->getHits() + 1); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [ 'message' => join(". ", $o->getMessages()), ]); } $h = new Hit(); $h->date = new \MongoDB\BSON\UTCDateTime(time() * 1000); $h->channel = $o->getChannel(); $h->mask = $mask; $h->victim = mb_strtolower($nick); $h->reason = $o->getReason(); if (false === $h->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [ 'message' => join(". ", $h->getMessages()), ]); } $dbTx->commit(); return $o; } public function akickExceptionFind() { return AkickException::find(); } public function drop($name, $oper, $reason, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'preoper', ''); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->enqueueDelete($o); $this->setStatus($name, Status::STATUS_DROPPED, $ip, $oper, $reason); $this->createHistory($name, History::EVENT_DROPPED, $ip, [ 'who' => $oper, 'reason' => $reason, ]); $dbTx->commit(); return $o; } public function delSuccessor($name, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if (strlen($o->getSuccessor()) <= 0) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NO_SUCCESSOR); } if (mb_strtolower($o->getSuccessor()) != mb_strtolower($nick)) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUCCESSOR_MISMATCH); } $o = $this->update($o, [ 'successor' => new \Phalcon\Db\RawValue("NULL"), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->createHistory($name, History::EVENT_UNSET_SUCCESSOR, $ip, [ 'who' => $nick, ]); $dbTx->commit(); return $o; } public function listForbidAll($cached = false) { if ($cached === true) { return Forbid::find([ 'cache' => [ 'key' => 'channel-forbids-all', 'lifetime' => 3600, ], ]); } else { return Forbid::find(); } } public function countForbid() { return Forbid::count(); } public function getChannelsByPattern($pattern) { $matched = []; $list = $this->listAll(); foreach ($list as $o) { $name = str_replace('#', '', $o->getName()); if (preg_match('#'.$pattern.'#i', $name)) { $matched[] = $o; } } return $matched; } public function listForbid($page = 1) { return Forbid::find([ 'limit' => self::PAGE_SIZE, 'offset' => ($page - 1) * self::PAGE_SIZE, ]); } public function getForbid($id) { $o = Forbid::findFirst([ 'id = :id:', 'bind' => [ 'id' => $id, ], ]); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_NOT_FOUND); } return $o; } public function checkForbid($name, $cached = false) { $list = $this->listForbidAll($cached); foreach ($list as $o) { if (preg_match("#".$o->getPattern()."#i", str_replace('#', '', $name))) { return true; } } return false; } public function checkForbiddenRegisteredChannels(Forbid $f, $oper, $force, $ip) { $list = Channel::find(); foreach ($list as $o) { if (preg_match("#".$f->getPattern()."#i", str_replace('#', '', $o->getName()))) { if ($force === true) { /** * We have to drop the nick as it is not allowed to use it anymore */ $this->drop($o->getName(), $oper, 'El canal ya no puede usarse (FORBID)', $ip); } else { /** * We drop an exception as we warn that pattern will drop registered nicks * and it is not forced */ throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_REGISTERED_AFFECTED); } } } } public function newForbid(array $data, $oper, $force, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel'); $date = date('Y-m-d H:i:s'); $defaults = [ 'created_by' => $oper, 'created_at' => $date, 'updated_by' => $oper, 'updated_at' => $date, ]; $data = array_merge($defaults, $data); $o = new Forbid(); $o->assign($data); $this->checkForbiddenRegisteredChannels($o, $oper, $force, $ip); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_CREATE, [ 'message' => join('. ', $o->getMessages()), ]); } $dbTx->commit(); return $o; } public function updateForbid($id, array $data, $oper, $force, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel'); $o = $this->getForbid($id); $defaults = [ 'updated_by' => $oper, 'updated_at' => date('Y-m-d H:i:s'), ]; $data = array_merge($defaults, $data); $o->assign($data); $this->checkForbiddenRegisteredChannels($o, $oper, $force, $ip); if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } $dbTx->commit(); return $o; } public function deleteForbid($id, $oper) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($oper, 'devel'); $o = $this->getForbid($id); if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function getChannelAccess($channel, $nick) { $o = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => mb_strtolower($channel), 'nick' => mb_strtolower($nick), ], ]); return $o; } public function getLevel(/*Channel|string*/ $channel, $nick) { $nick = strtolower($nick); if (is_object($channel)) { $c = $channel; } else { $c = $this->get($channel, true); } // Channel owner if (mb_strtolower($c->getFounder()) == $nick) { return 500; } // Identified $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, $c->getName()); if ($json) { $identified = json_decode($json, true); } else { $identified = []; } if (in_array($nick, $identified)) { return 500; } // Sucessor if (mb_strtolower($c->getSuccessor()) == $nick) { return self::SUCCESSOR_LEVEL; } // Register $a = $this->getChannelAccess($c->getName(), $nick); if ($a) { return $a->getLevel(); } return 0; } public function checkLevel(/*Channel|string*/ $channel, $level, $nick) { $nick = strtolower($nick); if (is_object($channel)) { $c = $channel; } else { $c = $this->get($channel, true); } $userlevel = 0; $is_founder = false; if (mb_strtolower($c->getFounder()) == $nick) { $userlevel = 500; $is_founder = true; } else { $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, $c->getName()); if ($json) { $identified = json_decode($json, true); } else { $identified = []; } if (in_array($nick, $identified)) { $userlevel = 500; $is_founder = true; } elseif ($c->getSuccessor() && mb_strtolower($c->getSuccessor()) == $nick) { $userlevel = self::SUCCESSOR_LEVEL; } else { $a = $this->getChannelAccess($c->getName(), $nick); if ($a) { $userlevel = $a->getLevel(); } } } if (!is_numeric($level)) { $levels = $this->normalizeLevels(json_decode($c->getLevels(), true)); if ($levels[$level] === 'DIS' || $levels[$level] === 'DISABLED') { if ($level === 'AUTOOP' && $is_founder === true) { return true; } return false; } if ($level === 'NOJOIN' || $level === 'AUTODEOP' || $level === 'AUTODEVOICE') { return $userlevel <= $levels[$level]; } if ($levels[$level] === 0 && ($level === 'AUTOOP' || $level === 'AUTOVOICE')) { return false; } return $userlevel >= $levels[$level]; } return $userlevel >= $level; } public function checkInvite($channel, $nick) { return $this->checkLevel($channel, 'INVITE', $nick); } public function checkVoice($channel, $nick) { return $this->checkLevel($channel, 'VOICEDEVOICE', $nick); } public function checkDevoice($channel, $nick) { return $this->checkLevel($channel, 'VOICEDEVOICE', $nick); } public function checkOp($channel, $nick) { return $this->checkLevel($channel, 'OPDEOP', $nick); } public function checkDeop($channel, $nick) { return $this->checkLevel($channel, 'OPDEOP', $nick); } public function checkUnban($channel, $nick) { return $this->checkLevel($channel, 'UNBAN', $nick); } public function checkTopic($channel, $nick) { return $this->checkLevel($channel, 'TOPIC', $nick); } public function checkBlogger($channel, $nick) { return $this->checkLevel($channel, 'BLOGGER', $nick); } public function checkForum($channel, $nick) { return $this->checkLevel($channel, 'FORUM', $nick); } public function delaccess($channel, $nick, $ip) { $dbTx = (new PhalconTxManager())->get(); $nick = mb_strtolower($nick); $c = $this->get($channel, true); if ($c->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $a = $this->getChannelAccess($channel, $nick); if ($a) { if ($a->getLevel() < 0) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NEGATIVE_REGISTER); } else { if (false === $a->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [ 'message' => join('. ', $a->getMessages()), ]); } } } else { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND); } $this->createHistory($c->getName(), History::EVENT_DELACCESS, $ip, [ 'nick' => $nick, ]); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->createHistory($nick, History::EVENT_DELACCESS, $ip, [ 'channel' => $channel, ]); $this->enqueue($c); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($channel); $dbTx->commit(); return $a; } public function getStatusAll() { return Status::find(); } public function getStatusList($status, $page = 1) { return Status::find([ [ 'status' => (int)$status, ], 'limit' => self::PAGE_SIZE, 'skip' => ($page - 1) * self::PAGE_SIZE, ]); } public function getStatus($channel) { return Status::findFirst([ [ 'channel' => mb_strtolower($channel), ], ]); } public function setStatus($channel, $status, $ip, $nick, $reason = '', $password = '', $description = '', $email = '') { $o = $this->getStatus($channel); if (!$o) { $o = new Status(); $o->channel = mb_strtolower($channel); } $o->ip = $ip; $o->nick = mb_strtolower($nick); $o->status = $status; if ($o->status == Status::STATUS_REQUESTED) { $o->founder = $o->nick; } $o->ts = time(); $o->reason = $reason; $o->password = $password; $o->description = $description; $o->email = $email; if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [ 'message' => join('. ', $o->getMessages()), ]); } return $o; } public function comment($channel, $nick, $ip, $comment) { return $this->createHistory($channel, History::EVENT_COMMENT, $ip, [ 'who' => $nick, 'comment' => $comment, ]); } public function getIdentified($channel) { $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel)); if ($json) { $nicks = json_decode($json, true); } else { $nicks = []; } return $nicks; } public function isIdentified($channel, $nick) { $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel)); if ($json) { $nicks = json_decode($json, true); } else { $nicks = []; } return in_array(mb_strtolower($nick), $nicks); } public function identify($channel, $password, $nick, $ip) { $nick = mb_strtolower($nick); $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } if ($o->getFounder() == mb_strtolower($nick)) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_ALREADY_FOUNDER); } if (false === $this->checkLevel($o, 'IDENTIFY', $nick)) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } if (!$this->getDI()->get('security')->checkHash($password, $o->getPassword())) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_BAD_PASSWORD); } $this->setIdentify($channel, $nick, true); $this->enqueueIdentify($o, $nick, "1"); $this->createHistory($o->getName(), History::EVENT_IDENTIFY, $ip, [ 'who' => $nick, ]); $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->createHistory($nick, History::EVENT_IDENTIFY, $ip, [ 'name' => $o->getName(), ]); } public function setIdentify($channel, $nick, $triggerException = false) { $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel)); if ($json) { $nicks = json_decode($json, true); if (in_array($nick, $nicks)) { if ($triggerException == true) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NICK_ALREADY_IDENTIFIED); } else { return; } } } else { $nicks = []; } $nicks[] = $nick; $redis->hSet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel), json_encode($nicks)); } public function unidentify($channel, $nick) { $nick = mb_strtolower($nick); $o = $this->get($channel, true); $redis = $this->getDI()->get('redis_cluster'); $json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel)); if ($json) { $nicks = json_decode($json, true); if (!in_array($nick, $nicks)) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_NICK_NOT_IDENTIFIED); } $nicks = array_diff($nicks, [$nick]); $redis->hSet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel), json_encode($nicks)); } $this->enqueueIdentify($o, $nick, "0"); } public function unidentifyChannel($channel) { $o = $this->get($channel, true); // NOTE: We get the identified list before delete to send to Socket later $list = $this->getIdentified($channel); $redis = $this->getDI()->get('redis_cluster'); $redis->hDel(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel)); // NOTE: We send to socket the unidentified list foreach ($list as $nick) { $this->enqueueIdentify($o, $nick, "0"); } } public function unidentifyAll() { $redis = $this->getDI()->get('redis_cluster'); $redis->del(self::REDIS_HASH_CHANNEL_IDENTIFY); // NOTE: We do not send to Socket because this is only a services burst reset } public function info($bot, $channel, $nick, $ip, $oper = false) { if ($oper === true) { $nick_manager = $this->getDI()->get('inspircd_nick_manager'); $nick_manager->checkOperator($nick, 'preoper'); } $s = $this->getStatus($channel); if (!$s) { $s = new Status(); $s->channel = mb_strtolower($channel); $s->status = Status::STATUS_NOT_REGISTERED; } $messages = [ $bot->buildMessage("Information from channel %channel%:", [ 'channel' => $channel, ]), " ".$bot->buildMessage("Status").": ".$bot->buildMessage($s->getStatusName()), ]; try { $o = $this->get($channel, true); if ($o->getIsSuspended() == 1) { $messages[] = " ".$bot->buildMessage("Suspend reason").": ".$o->getSuspendReason(); if ($oper === true) { $messages[] = " ".$bot->buildMessage("Suspended by").": ".$o->getSuspendBy(); } $messages[] = " ".$bot->buildMessage("Suspended until").": ".date('Y-m-d H:i:s', $o->getSuspendTs() + $o->getSuspendDuration()); } $messages[] = " ".$bot->buildMessage("Section").": ".(strlen($o->getSection()) <= 0 ? "-" : $o->getSection()); if ($o->getIg() == 1) { $messages[] = " ".$bot->buildMessage("It is a general interest channel.", []); } $messages[] = " ".$bot->buildMessage("Founder").": ".($o->getFounder() ? $o->getFounder() : $bot->buildMessage("Without founder")); if ($o->getSuccessor()) { $messages[] = " ".$bot->buildMessage("Successor").": ".$o->getSuccessor(); } $messages[] = " ".$bot->buildMessage("Description").": ".$o->getDescription(); $messages[] = " ".$bot->buildMessage("Registered").": ".date('Y-m-d H:i:s', $o->getTimeRegistered()); $messages[] = " ".$bot->buildMessage("Last use").": ".date('Y-m-d H:i:s', $o->getTimeLastUse()); $options = $o->getOptions(!$oper); if (($options['noexpire'] === false || $options['noexpire'] === 0) && $o->getIg() != 1) { if ($o->getTimeLastUse()) { $messages[] = " ".$bot->buildMessage("Expires at").": ".date('Y-m-d H:i:s', $o->getTimeLastUse() + self::CHANNEL_EXPIRE_DAYS * 24 * 3600); } else { $messages[] = " ".$bot->buildMessage("Expires at").": ".date('Y-m-d H:i:s', $o->getTimeRegistered() + self::CHANNEL_EXPIRE_DAYS * 24 * 3600); } } $levels = $this->normalizeLevels(json_decode($o->getLevels(), true)); // We only show topic and entrymsg information if user is an operator or is not blocked by NOJOIN level if ($oper === true || false === $this->checkLevel($channel, 'NOJOIN', $nick)) { if (strlen($o->getLastTopic()) > 0) { $messages[] = " ".$bot->buildMessage("Last topic").": ".$o->getLastTopic(); $messages[] = " ".$bot->buildMessage("Topic set by").": ".$o->getLastTopicBy(); $messages[] = " ".$bot->buildMessage("Topic set on").": ".date('Y-m-d H:i:s', $o->getLastTopicTime()); } else { $messages[] = " ".$bot->buildMessage("No topic set"); } if (strlen($o->getEntrymsg())) { $messages[] = " ".$bot->buildMessage("Entry message").": ".$o->getEntrymsg(); } else { $messages[] = " ".$bot->buildMessage("No entry message set"); } } if ($o->getUrl()) { $messages[] = " URL: ".$o->getUrl(); } try { $blog_manager = $this->getDI()->get('blog_manager'); if ($blog_manager->countPosts($o->getName()) > 0) { $config = $this->getDI()->get('config'); $messages[] = " ".$bot->buildMessage("Blog").": ".$config->application->baseUri.'canal/'.$o->getNamePretty().'/blog'; } } catch (\Exception $e) { } $allopts = $o->getOptions(false); if ($allopts['forum'] === true) { $config = $this->getDI()->get('config'); $s = $o->getSectionObj(); if ($s) { $messages[] = " ".$bot->buildMessage("Forum").": ".$config->discourse->baseUri.'/c/'.$s->getSlug().'/'.$o->getNamePretty(); } } if ($o->getEmail()) { $messages[] = " ".$bot->buildMessage("Email").": ".$o->getEmail(); } $messages[] = " ".$bot->buildMessage("Options").":"; foreach ($options as $opt => $v) { $messages[] = " ".mb_strtoupper($opt).": ".$bot->buildMessage($v ? "Activated" : "Deactivated", []); } $messages[] = " ".$bot->buildMessage("Modes lock").": ".$o->getMlock(); } catch (\Exception $e) { } $messages[] = $bot->buildMessage("End of information from channel %channel%.", [ 'channel' => $channel, ]); return $messages; } public function checkAccess($channel, $identity) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $c = $irc_manager->getChannel($channel); if ($c && isset($c['modes']) && preg_match('/(s|p)/', $c['modes'])) { $o = $this->get($channel, true); if ($o && mb_strtolower($o->getFounder()) == mb_strtolower($identity['selected_nick'])) { return; } $a = Access::findFirst([ 'channel = :channel: AND nick = :nick:', 'bind' => [ 'channel' => mb_strtolower($channel), 'nick' => (isset($identity['selected_nick']) ? mb_strtolower($identity['selected_nick']) : ''), ], ]); if ($a && $a->getLevel() > 0) { return; } throw new Exception(null, ErrorCodes::ERR_CHANNEL_IS_PRIVATE); } } public function getChannelsBySection($section, $limit = -1, $exclude = '') { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $minimum_nicks = $this->getDI()->get('config')->channels->important->minimum_nicks; $list = Channel::find([ 'section = :section:', 'bind' => [ 'section' => $section, ], ]); $temp = []; foreach ($list as $o) { if ($o->getIsSuspended() != 1) { $obj = $irc_manager->getChannel($o->getName()); $sheet = $o->getDatasheet(); if ($sheet || $obj && isset($obj['modes']) && !preg_match('/(i|R|s|p|k)/', $obj['modes'])) { if (mb_strtolower($o->getName()) != mb_strtolower($exclude)) { $c = $obj && isset($obj['cnt_members']) ? $obj['cnt_members'] : 0; if (!isset($temp[$c])) { $temp[$c] = []; } $temp[$c][] = $o; } } } } ksort($temp, SORT_NUMERIC); $temp = array_reverse($temp, true); $channels = []; foreach ($temp as $i => $list) { foreach ($list as $o) { if ($i >= $minimum_nicks || $o->getDatasheet()) { $channels[] = [ 'obj' => $o, 'users' => $i, ]; } } } if ($limit > 0) { $channels = array_slice($channels, 0, $limit); } return $channels; } public function getRandomDatasheet() { $list = Datasheet::find([ 'order' => 'RAND() DESC', 'limit' => 10, ]); foreach ($list as $o) { $c = $o->getChannelObj(); if ($c && $c->getSection() != 'ADU' && $c->getSection() != 'GAY' && $c->getSection() != 'LES') { return $o; } } return false; } public function createChannelSection($request) { $default = [ 'parent' => new \Phalcon\Db\RawValue(''), ]; $dbTx = (new PhalconTxManager())->get(); $o = new ChannelSection(); if (is_array($request)) { $o->assign(array_merge($default, $request)); } else { $o->assign(array_merge($default, $request->getPost())); } if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'message' => implode('. ', $o->getMessages()), ]); } if (!is_array($request)) { $this->updateChannelSectionImages($request, true); } $dbTx->commit(); return $o; } public function saveChannelSection($request) { $default = [ 'parent' => new \Phalcon\Db\RawValue(''), ]; $dbTx = (new PhalconTxManager())->get(); if (is_array($request)) { $o = $this->getSection(isset($request['code']) ? $request['code'] : ''); $o->assign(array_merge($default, $request)); } else { $o = $this->getSection($request->getPost('code', 'string', '')); $o->assign(array_merge($default, $request->getPost())); } if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_UPDATE, [ 'message' => implode('. ', $o->getMessages()), ]); } if (!is_array($request)) { $this->updateChannelSectionImages($request, false); } $dbTx->commit(); return $o; } protected function updateChannelSectionImages($request, $require_files = false) { if (count($request->getUploadedFiles()) < 1) { if (true === $require_files) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [ 'message' => 'You missed to upload images.', ]); } else { return; } } $cdn_config = $this->getDI()->get('config')->cdn->toArray(); $env = trim(file_get_contents(__DIR__.'/../../../../config/environment.txt')); foreach ($request->getUploadedFiles() as $file) { if ($file->getName() == '') { continue; } if ($file->getKey() == 'image_off' || $file->getKey() == 'image_on') { if ($file->getKey() == 'image_off') { $fname = $cdn_config['path'].'/channels/sections/'.$request->getPost('code', 'string', '').'-off.png'; } else { $fname = $cdn_config['path'].'/channels/sections/'.$request->getPost('code', 'string', '').'-on.png'; } Graphics::resizeW($file->getTempName(), $file->getTempName(), 1024); Graphics::crop($file->getTempName(), $file->getTempName(), 0, 0, 1024, 520); $file->moveTo($fname); } } if ($env == 'prod') { foreach ($request->getUploadedFiles() as $file) { if ($file->getName() == '') { continue; } if ($file->getKey() == 'image_off' || $file->getKey() == 'image_on') { if ($file->getKey() == 'image_off') { $fname = $cdn_config['path'].'/channels/sections/'.$request->getPost('code', 'string', '').'-off.png'; $name = $request->getPost('section', 'string', '').'-off.png'; } else { $fname = $cdn_config['path'].'/channels/sections/'.$request->getPost('code', 'string', '').'-on.png'; $name = $request->getPost('section', 'string', '').'-on.png'; } foreach ($cdn_config['nodes'] as $node) { if ($this->request->getServerAddress() != $node['host']) { try { $cdn = new Cdn($node['host'], $node['user'], $node['passwd'], 'channels/sections'); $cdn->connect(); $cdn->upload([ $fname => $file->getName(), ]); $cdn->disconnect(); } catch (\Exception $e) { $this->getDI()->get('redis_cluster')->rPush('chathispano_ftp_pending', json_encode([ 'server' => $node['host'], 'user' => $node['user'], 'passwd' => $node['passwd'], 'path' => $fname, 'folder' => 'channels/sections', 'name' => $name, ])); } } } } } } } public function getDatasheets() { return Datasheet::find([ 'order' => 'channel ASC', ]); } public function getDatasheet($channel) { $o = Datasheet::findFirstByChannel($channel); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [ 'name' => $channel, ]); } return $o; } public function getDatasheetBySlug($slug) { $o = Datasheet::findFirstBySlug($slug); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [ 'name' => $slug, ]); } return $o; } public function getRandomDatasheets($amount = 10) { return Datasheet::find([ "section <> 'ADU' AND section <> 'GAY' AND section <> 'LES'", 'order' => 'RAND() DESC', 'limit' => $amount, ]); } public function createChannelDatasheet($request) { if (is_array($request)) { $c = Channel::findFirstByName(isset($request['channel']) ? $request['channel'] : ''); } else { $c = Channel::findFirstByName($request->getPost('channel', 'string', '')); } if (!$c) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_REQUIRE_REGISTERED_CHANNEL); } $dbTx = (new PhalconTxManager())->get(); $o = new Datasheet(); if (is_array($request)) { $o->assign($request); } else { $o->assign($request->getPost()); } $o->setSection($c->getSection()); if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [ 'message' => implode('. ', $o->getMessages()), ]); } if (!is_array($request)) { $this->updateChannelDatasheetImage($request, true); } $dbTx->commit(); return $o; } public function saveChannelDatasheet($request) { if (!is_array($request)) { $dbTx = (new PhalconTxManager())->get(); } if (is_array($request)) { $o = $this->getDatasheetBySlug(isset($request['slug']) ? $request['slug'] : ''); $o->assign($request); } else { $o = $this->getDatasheetBySlug($request->getPost('slug', 'string', '')); $o->assign($request->getPost()); } if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_UPDATE, [ 'message' => implode('. ', $o->getMessages()), ]); } if (!is_array($request)) { $this->updateChannelDatasheetImage($request, false); $dbTx->commit(); } return $o; } public function dropChannelDatasheet($slug) { $o = $this->getDatasheetBySlug($slug); if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_DELETE, [ 'message' => implode('. ', $o->getMessages()), ]); } return $o; } protected function updateChannelDatasheetImage($request, $require_files = false) { if (count($request->getUploadedFiles()) < 1) { if (true === $require_files) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [ 'message' => 'You missed to upload images.', ]); } else { return; } } $cdn_config = $this->getDI()->get('config')->cdn->toArray(); $path = $cdn_config['path'].'/channels/datasheet/'; $env = trim(file_get_contents(__DIR__.'/../../../../config/environment.txt')); foreach ($request->getUploadedFiles() as $file) { if ($file->getName() == '') { continue; } if ($file->getKey() == 'image') { Graphics::resizeW($file->getTempName(), $file->getTempName(), 1024); $fname = mb_strtolower($request->getPost('slug', 'string', '')).'.png'; $file->moveTo($path.$fname); } } if ($env == 'prod') { foreach ($request->getUploadedFiles() as $file) { if ($file->getName() == '') { continue; } if ($file->getKey() == 'image') { $fname = mb_strtolower($request->getPost('slug', 'string', '')).'.png'; foreach ($cdn_config['nodes'] as $node) { if ($request->getServerAddress() != $node['host']) { try { $cdn = new Cdn($node['host'], $node['user'], $node['passwd'], 'channels/datasheet'); $cdn->connect(); $cdn->upload([ $path.$fname => $fname, ]); $cdn->disconnect(); } catch (\Exception $e) { $this->getDI()->get('redis_cluster')->rPush('chathispano_ftp_pending', json_encode([ 'server' => $node['server'], 'user' => $node['user'], 'passwd' => $node['passwd'], 'path' => $path.$fname, 'folder' => 'channels/datasheet', 'name' => $fname, ])); } } } } } } } public function getOverrides() { return Override::find([ 'order' => 'channel ASC', ]); } public function getOverride($channel) { $o = Override::findFirstByChannel($channel); if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [ 'name' => $channel, ]); } return $o; } public function createChannelOverride($request) { if (is_array($request)) { $o = Channel::findFirstByName(isset($request['channel']) ? $request['channel'] : ''); } else { $o = Channel::findFirstByName($request->getPost('channel', 'string', '')); } if (!$o) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_REQUIRE_REGISTERED_CHANNEL); } $o = new Override(); if (is_array($request)) { $o->assign($request); } else { $o->assign($request->getPost()); } if (false === $o->create()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [ 'message' => implode('. ', $o->getMessages()), ]); } return $o; } public function saveChannelOverride($request) { if (is_array($request)) { $o = $this->getOverride(isset($request['channel']) ? $request['channel'] : ''); $o->assign($request); } else { $o = $this->getOverride($request->getPost('channel', 'string', '')); $o->assign($request->getPost()); } if (false === $o->save()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_UPDATE, [ 'message' => implode('. ', $o->getMessages()), ]); } return $o; } public function dropChannelOverride($channel) { $o = $this->getOverride($channel); if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_DELETE, [ 'message' => implode('. ', $o->getMessages()), ]); } return $o; } public function getBlogsData(User $o) { $data = []; $blog_manager = $this->getDI()->get('blog_manager'); $nicks = $o->getNicks(); foreach ($nicks as $n) { $channels = $n->getFounderChannels(); foreach ($channels as $c) { // We skip if we have already granted access if (isset($data[$c->getName()])) { continue; } // It does not have access to post if (!$this->checkBlogger($c, $n->getNick())) { continue; } $last_post = $blog_manager->getLastChannelPost($c->getName(), true); $data[$c->getNamePretty()] = [ 'name' => $c->getName(), 'pretty_name' => $c->getNamePretty(), 'total_posts' => $blog_manager->countPosts($c->getName(), true), 'published_posts' => $blog_manager->countPosts($c->getName(), false), 'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-', ]; } $channels = $n->getSuccessorChannels(); foreach ($channels as $c) { // We skip if we have already granted access if (isset($data[$c->getName()])) { continue; } // It does not have access to post if (!$this->checkBlogger($c, $n->getNick())) { continue; } $last_post = $blog_manager->getLastChannelPost($c->getName(), true); $data[$c->getNamePretty()] = [ 'name' => $c->getName(), 'pretty_name' => $c->getNamePretty(), 'total_posts' => $blog_manager->countPosts($c->getName(), true), 'published_posts' => $blog_manager->countPosts($c->getName(), false), 'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-', ]; } $channels = $n->getChannelRegisters(); foreach ($channels as $r) { // We skip if we have already granted access if (isset($data[$r->getChannel()])) { continue; } // It does not have access to post if (!$this->checkBlogger($r->getChannel(), $n->getNick())) { continue; } $last_post = $blog_manager->getLastChannelPost($r->getChannel(), true); $data[$r->getChannelPretty()] = [ 'name' => $r->getChannel(), 'pretty_name' => $r->getChannelPretty(), 'total_posts' => $blog_manager->countPosts($r->getChannel(), true), 'published_posts' => $blog_manager->countPosts($r->getChannel(), false), 'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-', ]; } } return $data; } public function getForumsData(User $o) { $data = []; $nicks = $o->getNicks(); foreach ($nicks as $n) { $channels = $n->getFounderChannels(); foreach ($channels as $c) { // We skip if we have already granted access if (isset($data[$c->getName()])) { continue; } // It does not have access to post if (!$this->checkForum($c, $n->getNick())) { continue; } $options = $c->getOptions(); $data[$c->getNamePretty()] = [ 'name' => $c->getName(), 'pretty_name' => $c->getNamePretty(), 'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false, 'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '', ]; } $channels = $n->getSuccessorChannels(); foreach ($channels as $c) { // We skip if we have already granted access if (isset($data[$c->getName()])) { continue; } // It does not have access to post if (!$this->checkForum($c, $n->getNick())) { continue; } $options = $c->getOptions(); $data[$c->getNamePretty()] = [ 'name' => $c->getName(), 'pretty_name' => $c->getNamePretty(), 'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false, 'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '', ]; } $channels = $n->getChannelRegisters(); foreach ($channels as $r) { // We skip if we have already granted access if (isset($data[$r->getChannel()])) { continue; } // It does not have access to post if (!$this->checkForum($r->getChannel(), $n->getNick())) { continue; } $c = $r->getChannelObj(); $options = $c->getOptions(); $data[$r->getChannelPretty()] = [ 'name' => $r->getChannel(), 'pretty_name' => $r->getChannelPretty(), 'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false, 'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '', ]; } } return $data; } public function activateForum($name, $nick, $ip) { $o = $this->get($name, true); if ($o->getIsSuspended() == 1) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED); } $nick_manager = $this->getDI()->get('inspircd_nick_manager'); if (false === $this->checkLevel($o, 'FORUM', $nick)) { try { $nick_manager->checkOperator($nick, 'devel'); } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED); } } try { $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->createChannel($o); $this->setOption($name, 'ChatHispano', 'forum', 'on', '127.0.0.1', false); } catch (\Exception $e) { throw new Exception(null, ErrorCodes::ERR_SERVICES_UNKNOWN, [ 'code' => $e->getMessage(), ]); } return $o; } protected function expireAkickList($list, $type, &$updatedChannels) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $redis = $this->getDI()->get('redis_cluster'); foreach ($list as $o) { try { if (false === $o->delete()) { $msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 ".$o->getChannel()."\x02 Mask=\x02 ".$o->getMask()."\x02 Message=\x02 ".join(". ", $o->getMessages()); $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } else { $redis->set('chathispano_inspircd_akick_delete_'.str_replace('#', '', $o->getChannel()).'_'.$o->getMask(), 1, 3600 * 24); if (!in_array($o->getChannel(), $updatedChannels)) { $updatedChannels[] = $o->getChannel(); } $msg = "\x02[AKICK] [EXPIRE] Channel=\x02 ".$o->getChannel()."\x02 Mask=\x02 ".$o->getMask()."\x02 Date=\x02 ".$o->getCreatedOn()."\x02 Hits=\x02 ".$o->getHits()."\x02 LastHit=\x02 ".$o->getLastHit()."\x02 Type=\x02 ".$type; $irc_manager->privmsgOrderEnqueue('AAAAAA', '#chan', $msg); $irc_manager->noticeOrderEnqueue('AAAAAA', '@'.$o->getChannel(), "El akick ".$o->getMask()." ha expirado"); $this->createHistory($o->getChannel(), History::EVENT_AKICK_EXPIRE, '127.0.0.1', [ $o->getMask(), ]); } } catch (\Exception $e) { $msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 ".$o->getChannel()."\x02 Mask=\x02 ".$o->getMask()."\x02 Message=\x02 ".$e->getMessage(); $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } } } protected function expireNegativeRegisters($list, $type, &$updatedChannels) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $redis = $this->getDI()->get('redis_cluster'); foreach ($list as $o) { try { if (false === $o->delete()) { $msg = "\x02\x034[ERROR] [ACCESS] [EXPIRE]\x03 Channel=\x02 ".$o->getChannel()."\x02 Nick=\x02 ".$o->getNick()."\x02 Message=\x02 ".join(". ", $o->getMessages()); $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } else { $redis->set('chathispano_inspircd_negative_registers_delete_'.str_replace('#', '', $o->getChannel()).'_'.$o->getNick(), 1, 3600 * 24); if (!in_array($o->getChannel(), $updatedChannels)) { $updatedChannels[] = $o->getChannel(); } $msg = "\x02[ACCESS] [EXPIRE] Channel=\x02 ".$o->getChannel()."\x02 Nick=\x02 ".$o->getNick()."\x02 Date=\x02 ".date('Y-m-d H:i:s', $o->getSetOn())."\x02 LastHit=\x02 ".date('Y-m-d H:i:s', $o->getLastUse())."\x02 Type=\x02 ".$type; $irc_manager->privmsgOrderEnqueue('AAAAAA', '#chan', $msg); $irc_manager->noticeOrderEnqueue('AAAAAA', '@'.$o->getChannel(), "El registro -1 ".$o->getNick()." ha expirado"); $this->createHistory($o->getChannel(), History::EVENT_ACCESS_EXPIRE, '127.0.0.1', [ $o->getNick(), ]); } } catch (\Exception $e) { $msg = "\x02\x034[ERROR] [ACCESS] [EXPIRE]\x03 Channel=\x02 ".$o->getChannel()."\x02 Nick=\x02 ".$o->getNick()."\x02 Message=\x02 ".$e->getMessage(); $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } } } public function expireAkicks() { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $updatedChannels = []; // Expire akicks with no use and 7 days age $list = Akick::find([ "hits = 0 AND created_on < :date:", "bind" => [ "date" => date('Y-m-d H:i:s', strtotime("now -7 days")), ], "order" => "channel ASC", ]); $this->expireAkickList($list, 'NOHITS', $updatedChannels); // Expire akicks with no hits in the last 30 days $list = Akick::find([ "hits > 0 AND last_hit < :date:", "bind" => [ "date" => date('Y-m-d H:i:s', strtotime("now -30 days")), ], "order" => "channel ASC", ]); $this->expireAkickList($list, 'NOHITS30D', $updatedChannels); // Expire akicks with 90 days age $list = Akick::find([ "created_on < :date:", "bind" => [ "date" => date('Y-m-d H:i:s', strtotime("now -90 days")), ], "order" => "channel ASC", ]); $this->expireAkickList($list, '90DOLD', $updatedChannels); $list = Access::find([ 'level = -1 AND set_on < :date: AND last_use IS NULL', 'bind' => [ "date" => strtotime("now -7 days"), ], 'order' => 'channel ASC', ]); $this->expireNegativeRegisters($list, 'NOHITS', $updatedChannels); $list = Access::find([ 'level = -1 AND last_use IS NOT NULL AND last_use < :date:', 'bind' => [ "date" => strtotime("now -30 days"), ], 'order' => 'channel ASC', ]); $this->expireNegativeRegisters($list, 'NOHITS30D', $updatedChannels); $list = Access::find([ 'level = -1 AND set_on < :date:', 'bind' => [ "date" => strtotime("now -90 days"), ], 'order' => 'channel ASC', ]); $this->expireNegativeRegisters($list, '90OLD', $updatedChannels); // Send updated channels to servers foreach ($updatedChannels as $channel) { $o = Channel::findFirst([ "name = :name:", "bind" => [ "name" => $channel, ], ]); if (!$o) { $msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 ".$channel."\x02 Message=\x02 Channel not found"; $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } else { $this->enqueue($o); } } } protected function expireSuspend(Channel $o) { $dbTx = (new PhalconTxManager())->get(); try { $this->update($o, [ 'is_suspended' => 0, 'suspend_by' => new \Phalcon\Db\RawValue("NULL"), 'suspend_reason' => new \Phalcon\Db\RawValue("NULL"), 'suspend_ts' => new \Phalcon\Db\RawValue("NULL"), 'suspend_duration' => new \Phalcon\Db\RawValue("NULL"), ]); $discourse_manager = $this->getDI()->get('discourse_manager'); $discourse_manager->updateChannel($o->getName()); $this->setStatus($o->getName(), Status::STATUS_REGISTERED, '127.0.0.1', $o->getFounder()); $c = $this->get($o->getName(), true); $this->createHistory($o->getName(), History::EVENT_EXPIRE_SUSPEND, '127.0.0.1', []); $this->enqueue($c); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $msg = "\x02[SUSPEND] [EXPIRE] Channel=\x02 ".$o->getName(); $irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg); $dbTx->commit(); } catch (\Exception $e) { $dbTx->rollback(); } } public function expireSuspends($console) { $list = $this->listSuspendExpired(); $cnt = 0; foreach ($list as $o) { try { $this->expireSuspend($o); $cnt++; } catch (\Exception $e) { $dbTx = (new PhalconTxManager())->get(); $dbTx->rollback(); } } $console->consoleLog(">>> Expired ".$cnt." channel suspends", 'yellow'); } protected function expireChannel(Channel $o) { $dbTx = (new PhalconTxManager())->get(); try { $founder = $o->getFounderObj(); if (false === $o->delete()) { throw new Exception(null, ErrorCodes::ERR_CHANNEL_DELETE, [ 'message' => join('. ', $o->getMessages()), ]); } $this->setStatus($o->getName(), Status::STATUS_NOT_REGISTERED, '127.0.0.1', 'CHaN'); $this->createHistory($o->getName(), History::EVENT_EXPIRED, '127.0.0.1', []); $this->enqueueDelete($o); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $msg = "\x02\x034[EXPIRED]\x03 Name=\x02 ".$o->getName()."\x02 Last use=\x02 ".date('Y-m-d H:i:s', $o->getTimeLastUse()); $irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg); if ($founder) { $mailer = $this->getDI()->get('mail'); $mailer->addTo($founder->getEmail()); $mailer->setLanguage('es'); $mailer->send( 'Chat Hispano', '[ChatHispano] El canal '.$o->getName().' ha expirado', 'channel_expired', null, [ 'name' => $o->getName(), 'nick' => $founder->getEmail(), 'last_use' => date('Y-m-d H:i:s', $o->getTimeLastUse()), 'expire_days' => self::CHANNEL_EXPIRE_DAYS, 'images' => [ 'logo' => 'public/assets/backoffice/img/logo-medium.jpg', ], ] ); } $dbTx->commit(); } catch (\Exception $e) { $dbTx->rollback(); } } protected function expireWarnChannel(Channel $o) { $this->setOption($o->getName(), 'ChatHispano', 'expirewarn', 'on', '127.0.0.1', false); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $msg = "\x02\x038[EXPIRE WARN]\x03 Name=\x02 ".$o->getName()."\x02 Last use=\x02 ".date('Y-m-d H:i:s', $o->getTimeLastUse()); $irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg); $founder = $o->getFounderObj(); if ($founder) { $mailer = $this->getDI()->get('mail'); $mailer->addTo($founder->getEmail()); $mailer->setLanguage('es'); $mailer->send( 'Chat Hispano', '[ChatHispano] Aviso de expiración del canal '.$o->getName(), 'channel_expire_warn', null, [ 'name' => $o->getName(), 'nick' => $founder->getEmail(), 'last_use' => date('Y-m-d H:i:s', $o->getTimeLastUse()), 'expire_days' => self::CHANNEL_EXPIRE_DAYS, 'images' => [ 'logo' => 'public/assets/backoffice/img/logo-medium.jpg', ], ] ); } } public function expire($console) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $expire_ts = time() - (self::CHANNEL_EXPIRE_DAYS * 24 * 3600); $expire_warn = time() - (self::CHANNEL_WARN_EXPIRE_DAYS * 24 * 3600); $list = Channel::find([ 'time_last_use < :time_last_use:', 'bind' => [ 'time_last_use' => $expire_warn, ], ]); $cnt = 0; $warn = 0; $suspended = 0; $noexpire = 0; foreach ($list as $o) { try { $options = $o->getOptions(); if ($o->getIsSuspended() == 1) { /** * We do not expire suspended channels */ $suspended++; continue; } if ($o->getIg() == 1 || $options['noexpire'] === true) { /** * We do not expire IG channels or with NOEXPIRE */ $noexpire++; continue; } if ($o->getTimeLastUse() == null || $o->getTimeLastUse() < $expire_ts) { $this->expireChannel($o); $cnt++; } else { if ($options['expirewarn'] === true) { /** * Channel is already warned */ continue; } $this->expireWarnChannel($o); $warn++; } } catch (\Exception $e) { $console->consoleLog(">>> Error: ".$e->getMessage()." ".$e->getCode(), 'red'); $msg = "\x02\x038[ERROR]\x03 Message=\x02 ".$e->getMessage(); $irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg); } } $console->consoleLog(">>> Not expiring ".$suspended." SUSPENDED channels", 'green'); $console->consoleLog(">>> Not expiring ".$noexpire." channels with NOEXPIRE", 'green'); $console->consoleLog(">>> Total ".$warn." channels warned", 'yellow'); $console->consoleLog(">>> Total ".$cnt." channels expired", 'red'); } protected function enqueueDelete(Channel $o) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $data = [ 'DATATYPE' => 'DELETE', 'obj' => [ 'obj' => 'CHANNEL', 'key' => $o->getName(), ], ]; $irc_manager->dataEnqueue($data); } public function enqueue(Channel $o) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $data = $o->socketExport(); $data['DATATYPE'] = 'CHANNEL'; $irc_manager->dataEnqueue($data); } protected function enqueueIdentify(Channel $o, $nick, $status) { $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $n = $irc_manager->getNick($nick); if ($n) { $irc_manager->dataEnqueue([ 'DATATYPE' => 'IDENTIFY', 'channel' => $o->getName(), 'nick' => $nick, 'status' => $status, ], $n['server_name']); } } } |
#14 | ChatHispanoEngine\Core\Managers\InspIRCd\ChannelManager->getRandomDatasheets /srv/ChatHispanoEngine/releases/94/apps/Web/Controllers/BaseController.php (254) <?php namespace ChatHispanoEngine\Web\Controllers; use ChatHispanoEngine\Core\Controllers\BaseController as CoreController; use ChatHispanoEngine\Core\Library\Util; use ChatHispanoEngine\Core\Library\Irc\IP; use ChatHispanoEngine\Core\Models\InspIRCd\Channel; class BaseController extends CoreController { protected $private_controllers = [ 'profile', ]; protected $private_actions = [ 'paywall' => [ 'checkoutSuccessPaypal', ], ]; protected $time_start; protected $enable_moment = false; protected $enable_editor = false; protected $enable_charts = false; protected $head_title; protected $head_suffix; protected $meta_description; protected $meta_site_name; protected $meta_show_image; protected $meta_image; protected $meta_twitter_profile; protected $meta_facebook_id; protected $meta_noindex; protected $meta_nofollow; protected $meta_article; protected $meta_article_tags; protected $meta_article_section; protected $meta_article_created; protected $meta_article_updated; protected $rel_canonical; protected function getDefaultMetaTags() { $config = $this->getDI()->get('config'); $this->head_title = $config->seo->head_title; $this->head_suffix = $config->seo->head_suffix; $this->meta_description = $config->seo->meta_description; $this->meta_site_name = $config->seo->meta_site_name; $this->meta_show_image = true; $this->meta_image = $config->seo->meta_image; $this->meta_twitter_profile = $config->seo->meta_twitter_profile; $this->meta_facebook_id = $config->seo->meta_facebook_id; $this->meta_noindex = $this->env == 'prod' ? false : true; $this->meta_nofollow = false; $this->article = false; $this->rel_canonical = ($this->request->getServer('HTTPS') ? 'https://' : 'http://') .$this->request->getServer('SERVER_NAME') .($this->request->getServer('REQUEST_URI') == '/' ? '' : $this->request->getServer('REQUEST_URI')); $controller = $this->dispatcher->getControllerName(); $action = $this->dispatcher->getActionName(); $seo = $config->seo->controllers->toArray(); if (isset($seo[$controller]) && isset($seo[$controller][$action])) { $this->head_title = $seo[$controller][$action]['title']; $this->meta_description = $seo[$controller][$action]['description']; if (isset($seo[$controller][$action]['nofollow']) && true === $seo[$controller][$action]['nofollow']) { $this->setMetaNofollow(true); } } } protected function setArticleMeta(array $meta_article_tags, $meta_article_section, $meta_article_created, $meta_article_updated) { $this->meta_article = true; $this->meta_article_tags = $meta_article_tags; $this->meta_article_section = $meta_article_section; $this->meta_article_created = $meta_article_created; $this->meta_article_updated = $meta_article_updated; } protected function setHeadTitle($head_title) { $this->head_title = $head_title; } protected function setMetaDescription($meta_description) { $this->meta_description = $meta_description; } protected function setMetaSiteName($meta_site_name) { $this->meta_site_name = $meta_site_name; } protected function setMetaImage($meta_image) { $this->meta_image = $meta_image; } protected function setMetaNofollow($meta_nofollow) { $this->meta_nofollow = $meta_nofollow; } protected function setMetaNoindex($meta_noindex) { $this->meta_noindex = $meta_noindex; } protected function setRelCanonical($rel_canonical) { $this->rel_canonical = $rel_canonical; } protected function setMetaTags() { $this->view->head_title = $this->head_title; $this->view->head_suffix = $this->head_suffix; $this->view->meta_description = $this->meta_description; $this->view->meta_site_name = $this->meta_site_name; $this->view->meta_show_image = $this->meta_show_image; $this->view->meta_image = $this->meta_image; $this->view->meta_facebook_id = $this->meta_facebook_id; $this->view->meta_twitter_profile = $this->meta_twitter_profile; $this->view->meta_noindex = $this->meta_noindex; $this->view->meta_nofollow = $this->meta_nofollow; $this->view->meta_article = $this->meta_article; if ($this->meta_article) { $this->view->meta_article_tags = $this->meta_article_tags; $this->view->meta_article_section = $this->meta_article_section; $this->view->meta_article_created = $this->meta_article_created; $this->view->meta_article_updated = $this->meta_article_updated; } $this->view->rel_canonical = $this->rel_canonical; } public function beforeExecuteRoute($dispatcher) { $this->view->cdn_uri = $this->config->cdn->baseUri; $this->translate->setDefaultDomain('web'); $controller = $this->dispatcher->getControllerName(); $action = $this->dispatcher->getActionName(); if ($controller == 'auth' && $action != 'session' && $action != 'logout' && $action != 'setNick' && $action != 'registerCompleted' && true === $this->auth->isUserSignedIn()) { $this->response->redirect(''); return false; } $this->view->section_sex = 0; $this->view->section_gay = 0; $this->view->section_lesbianas = 0; if (false === $this->auth->isUserSignedIn() && (in_array($controller, $this->private_controllers) || (isset($this->private_actions[$controller]) && in_array($action, $this->private_actions[$controller])))) { $this->flashSession->warning($this->_t('You have to login to access to this module.')); $this->response->redirect('auth/login'); $this->session->set('web_redirect_after_login', $this->request->getQuery('_url')); $dispatcher->forward([ 'controller' => 'auth', 'action' => 'login', ]); return false; } if ($controller == 'auth') { $redir = $this->request->getQuery('redir', 'string', ''); if ($redir != '') { if ($action == 'login') { $this->session->set('web_redirect_after_login', $redir); $this->session->remove('web_redirect_after_register'); } elseif ($action == 'register') { $this->session->remove('web_redirect_after_login'); $this->session->set('web_redirect_after_register', $redir); } } } /* * Getting environment and common template variables */ $this->getEnvironment(); /* * Building assets */ if ($controller == 'webchat') { $this->buildWebchatAssets(); } else { $this->buildAssets(); } if ($this->auth->isUserSignedIn() || $this->auth->checkAuthCookie()) { $this->view->loggedIn = true; $this->view->identity = $this->auth->syncIdentity(); $identity = $this->auth->getIdentity(); $this->view->loggedInUser = $this->getDI()->get('user_manager')->getByEmail($identity['email']); $this->view->hasPremium = $this->view->loggedInUser->hasSubscriptionType('premium'); if ($this->view->hasPremium) { $s = $this->view->loggedInUser->getSubscriptionType('premium'); $this->view->premiumSubscription = $s->getPlan()->getSlug(); } else { $this->view->premiumSubscription = false; } } else { $this->view->loggedIn = false; $this->view->hasPremium = false; } $this->getDefaultMetaTags(); $this->view->rating_avg = 4.9; $this->view->rating_best = 5; $this->view->rating_total = 5982; $this->view->client_ip = $this->request->getClientAddress(); $this->view->client_real_ip = $this->request->getClientAddress(true); try { $this->view->gline = $this->getDI()->get('inspircd_gline_manager')->findActiveByIp($this->view->client_real_ip); } catch (\Exception $e) { } $this->view->controller = $controller; $this->view->action = $action; $this->view->backLink = $this->request->getServer('HTTP_REFERER'); $this->view->baseUri = $this->config->application->baseUri; $queryString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '/'; $this->view->fullUri = $this->config->application->baseUri.substr($queryString, 1); $this->view->supportUri = $this->config->application->supportUri; $this->view->locale = $this->translate->getLanguage(); $this->view->chatmovilUri = $this->config->application->chatmovilUri; $this->view->kiwiUri = $this->config->application->kiwiUri; $this->view->current_year = date('Y'); $this->view->facebook_app_id = $this->config->facebook->app_id; /** * Random channel datasheets */ $this->view->random_channels = $this->getDI()->get('inspircd_channel_manager')->getRandomDatasheets(3); // Special content type in utils controller if ($this->view->controller == 'utils') { if ($this->view->action == 'sitemap') { $this->response->setHeader('Content-Type', 'text/xml; charset=utf-8'); } else { $this->response->setHeader('Content-Type', 'text/plain; charset=utf-8'); } } else { $this->response->setHeader('Content-Type', 'text/html; charset=utf-8'); } $this->view->cdnUri = $this->config->cdn->baseUri; // Ads config $this->view->ads_revive_enabled = false; // TODO: Temporary disabling revive ads except few pages if ($this->view->controller == 'stats' || ($this->view->controller == 'channel' && $this->view->action == 'stats') || $this->view->controller == 'stories') { // Always awin $this->view->ads_revive_enabled = true; // } else { // $rnd = rand(1, 100); // 70% bidding, 30% revive //$this->view->ads_revive_enabled = ($rnd >= 71 && $rnd <= 100); } // We add this to make revive work if (true === $this->view->ads_revive_enabled) { $this->response->setHeader('Access-Control-Allow-Origin', $this->request->getHTTPReferer()); } $this->view->ads_onnetwork_enabled = true; $this->view->ads_optimanetwork_enabled = false; // Refinery89 // TODO: setup a 50% chance traffic when tests are finished $this->view->refinery89_enabled = true; // Wechat version $this->view->enable_element = $this->config->webchat->enable_element; // Paywall promo $promo_enabled = $this->config->paywall->promo->enabled; $promo_start_time = $this->config->paywall->promo->start_time; $promo_end_time = $this->config->paywall->promo->end_time; $this->view->paywall_promo_enabled = $promo_enabled && time() >= strtotime($promo_start_time) && time() <= strtotime($promo_end_time); $this->view->paywall_promo_image = $this->config->paywall->promo->image; $this->view->paywall_promo_button_link = $this->config->paywall->promo->button_link; $this->view->paywall_promo_keyword_header = $this->_t($this->config->paywall->promo->keyword_header); $this->view->paywall_promo_keyword_description = $this->_t($this->config->paywall->promo->keyword_description); } public function afterExecuteRoute($dispatcher) { $this->view->enable_moment = $this->enable_moment; $this->view->enable_charts = $this->enable_charts; $this->view->enable_editor = $this->enable_editor; /* * Default META tags */ $this->setMetaTags(); } public function goToLastPage() { $this->response->redirect($this->request->getServer('HTTP_REFERER')); } /** * Translator. * * @param string $message */ protected function _t($message, $vars = null) { return $this->translate->translate($message, $vars, 'web'); } protected function buildResponse() { $response = (new \Phalcon\Http\Response()) ->setStatusCode(200, 'OK') ->setHeader('Access-Control-Allow-Headers', 'X-Requested-With'); return $response; } protected function checkSection($section) { $sex = 0; $gay = 0; $lesbianas = 0; switch ($section) { case 'ADU': $sex = 1; break; case 'LES': $lesbianas = 1; break; case 'GAY': $gay = 1; break; default: break; } $this->view->section_sex = $sex; $this->view->section_gay = $gay; $this->view->section_lesbianas = $lesbianas; } protected function checkChannelSection(Channel $channel) { /** * Getting section to know if it is a sex/gay/lesb channel or not * to put different ad zones (#1471) */ $lesbianas = 0; $gay = 0; $sex = 0; if ($channel) { $options = $channel->getOptions(); if ($options['noads'] == 1 || $options['noads'] == '1') { /** * If ads are manually disabled, we mark as adults to avoid showing ads */ $sex = 1; } else { try { $section = $channel->getSectionObj(); if ($section) { switch ($section->getCode()) { case 'ADU': $sex = 1; break; case 'LES': $lesbianas = 1; break; case 'GAY': $gay = 1; break; default: break; } } else { $debug_channel = $this->config->irc->opers_channel; $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $irc_manager->privmsgOrderEnqueue('AAAAAA', $debug_channel, "El canal\x02 ".$channel->getName()."\x02 no tiene sección en la BBDD"); $sex = 1; } } catch (\Exception $e) { /** * If we catch an error getting section, we avoid ads */ $sex = 1; } } } else { /** * If there is no channel, we avoid ads */ $sex = 1; } $this->view->section_sex = $sex; $this->view->section_gay = $gay; $this->view->section_lesbianas = $lesbianas; } protected function buildWebchatAssets() { $this->assets->collection('webchatCss') ->addInlineCss(file_get_contents(__DIR__.'/../../../public/assets/compiled/webchatCss.min.css')); $this->assets->collection('webchatJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/webchatJs.min.js')); $this->assets->collection('wpluginJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/wpluginJs.min.js')); } protected function buildAssets() { $this->assets->collection('headerCss') ->addInlineCss(file_get_contents(__DIR__.'/../../../public/assets/compiled/headerCss.min.css')); $this->assets->collection('mainJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/mainJs.min.js')); $this->assets->collection('pluginJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/pluginJs.min.js')); if ($this->enable_moment === true) { $this->assets->collection('momentJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/momentJs.min.js')); } if ($this->enable_charts === true) { $this->assets->collection('chartJs') ->addInlineJs(file_get_contents(__DIR__.'/../../../public/assets/compiled/chartJs.min.js')); } if ($this->enable_editor === true) { $baseUri = $this->config->application->baseUri; $this->assets->collection('ckeditorJs') ->addJs('assets/web/plugins/ckeditor/ckeditor.js') ->addJs('assets/web/plugins/ckeditor/lang/en.js') ->addJs('assets/web/plugins/ckeditor/lang/es.js') ->addJs('assets/web/plugins/ckeditor/lang/ca.js') ->addJs('assets/web/js/ckeditor/youtube/plugin.js') ->addJs('assets/web/js/ckeditor/youtube/lang/en.js') ->addJs('assets/web/js/ckeditor/youtube/lang/es.js'); } } } |
#15 | ChatHispanoEngine\Web\Controllers\BaseController->beforeExecuteRoute |
#16 | Phalcon\Dispatcher\AbstractDispatcher->dispatch |
#17 | Phalcon\Mvc\Application->handle /srv/ChatHispanoEngine/releases/94/apps/Application.php (150) <?php // namespace ChatHispanoEngine; /** * Application driver class to initialize Phalcon and * other resources. */ class Application extends \Phalcon\Mvc\Application { private static $mode = 'dev'; private static $DEFAULT_MODULE = 'api'; public const MODE_PRODUCTION = 'prod'; public const MODE_STAGING = 'staging'; public const MODE_TEST = 'test'; public const MODE_DEVELOPMENT = 'dev'; /** * Set application mode and error reporting level. */ public function __construct($defaultModule, $env = 'dev') { $this->modules = array( 'core' => array( 'className' => 'ChatHispanoEngine\Core\Module', 'path' => __DIR__.'/Core/Module.php', ), 'api' => array( 'className' => 'ChatHispanoEngine\Api\Module', 'path' => __DIR__.'/Api/Module.php', ), 'login' => array( 'className' => 'ChatHispanoEngine\Login\Module', 'path' => __DIR__.'/Login/Module.php', ), 'oidc' => array( 'className' => 'ChatHispanoEngine\Oidc\Module', 'path' => __DIR__.'/Oidc/Module.php', ), 'web' => array( 'className' => 'ChatHispanoEngine\Web\Module', 'path' => __DIR__.'/Web/Module.php', ), 'backoffice' => array( 'className' => 'ChatHispanoEngine\Backoffice\Module', 'path' => __DIR__.'/Backoffice/Module.php', ), 'movil' => array( 'className' => 'ChatHispanoEngine\Movil\Module', 'path' => __DIR__.'/Movil/Module.php', ), 'regwebexternal' => array( 'className' => 'ChatHispanoEngine\RegWebExternal\Module', 'path' => __DIR__.'/Regwebexternal/Module.php', ), 'cdn' => array( 'className' => 'ChatHispanoEngine\Cdn\Module', 'path' => __DIR__.'/Cdn/Module.php', ), 'shorten' => array( 'className' => 'ChatHispanoEngine\Shorten\Module', 'path' => __DIR__.'/Shorten/Module.php', ), ); static::$DEFAULT_MODULE = $defaultModule; self::$mode = $env; self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt')); define('ENVIRONMENT', self::$mode); if (!defined('PHALCON_MODE')) { $mode = getenv('PHALCON_MODE'); $mode = $mode ? $mode : self::$mode; define('PHALCON_MODE', $mode); } switch (self::getMode()) { case self::MODE_PRODUCTION: case self::MODE_STAGING: error_reporting(0); break; case self::MODE_TEST: case self::MODE_DEVELOPMENT: ini_set('display_errors', 'On'); error_reporting(E_ALL); break; } } /** * Register the services here to make them general or register in * the ModuleDefinition to make them module-specific. */ protected function _registerServices() { $defaultModule = self::$DEFAULT_MODULE; $modules = $this->modules; $config = include __DIR__.'/../config/config.php'; $env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php'; $config->merge($env_config); $di = new \Phalcon\DI\FactoryDefault(); include __DIR__.'/../config/loader.php'; include __DIR__.'/../config/services.php'; include __DIR__.'/../config/routing.php'; $this->setDI($di); } /** * Run the application. */ public function main() { if (static::MODE_PRODUCTION === static::getMode()) { $this->mainProd(); } else { $this->mainDev(); } } private function getRequestUri() { if (!isset($_SERVER)) { return "/"; } if (!is_array($_SERVER)) { return "/"; } if (!isset($_SERVER['REQUEST_URI'])) { return "/"; } return $_SERVER['REQUEST_URI']; } /** * Run the development environment. */ private function mainDev() { (new \Phalcon\Support\Debug())->listen(); $this->_registerServices(); $this->registerModules($this->modules); $response = $this->handle($this->getRequestUri()); $response->send(); } /** * Run the production environment. */ private function mainProd() { try { $this->registerModules($this->modules); $this->_registerServices(); $response = $this->handle($this->getRequestUri()); $response->send(); } catch (\Exception $e) { $logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log'); $msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")"; $msg .= "\n".$e->getTraceAsString(); $logger->process(new \Phalcon\Logger\Item($msg, "error", 100)); $logger->close(); // remove view contents from buffer ob_clean(); $errorCode = 500; $errorView = __DIR__.'/../public/errors/error.html'; if (401 === $e->getCode()) { // 401 UNAUTHORIZED $errorCode = 401; } elseif (403 === $e->getCode()) { // 403 FORBIDDEN $errorCode = 403; } elseif (404 === $e->getCode() || $e instanceof Phalcon\Mvc\View\Exception || $e instanceof Phalcon\Mvc\Dispatcher\Exception) { // 404 NOT FOUND $errorCode = 404; } // Get error view contents. Since we are including the view // file here you can use PHP and local vars inside the error view. ob_start(); include_once $errorView; $contents = ob_get_contents(); ob_end_clean(); // send view to header $response = $this->getDI()->getShared('response'); $response->resetHeaders() ->setStatusCode($errorCode, null) ->setContent($contents) ->send() ; /** * We try to register in MongoDB the error to be able to * track it in backoffice and/or receive emails */ try { $system_log_manager = $this->getDI()->get('system_log_manager'); if ($errorCode == 500) { $system_log_manager->createError([ 'ip' => $_SERVER['SERVER_ADDR'], 'host' => $_SERVER['SERVER_NAME'], 'process' => 'php-fpm', 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ]); } else { $system_log_manager->createWarning([ 'ip' => $_SERVER['SERVER_ADDR'], 'host' => $_SERVER['SERVER_NAME'], 'process' => 'php-fpm', 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ]); } } catch (\Exception $e) { } } } public function slowLog($t) { $config = $this->getDI()->get('config'); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $server = gethostname() ? gethostname() : 'unknown'; $uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; $msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI'] ."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri; $irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg); } /** * Get the current mode. * * @return string */ public static function getMode() { return self::$mode; } } |
#18 | Application->mainDev /srv/ChatHispanoEngine/releases/94/apps/Application.php (122) <?php // namespace ChatHispanoEngine; /** * Application driver class to initialize Phalcon and * other resources. */ class Application extends \Phalcon\Mvc\Application { private static $mode = 'dev'; private static $DEFAULT_MODULE = 'api'; public const MODE_PRODUCTION = 'prod'; public const MODE_STAGING = 'staging'; public const MODE_TEST = 'test'; public const MODE_DEVELOPMENT = 'dev'; /** * Set application mode and error reporting level. */ public function __construct($defaultModule, $env = 'dev') { $this->modules = array( 'core' => array( 'className' => 'ChatHispanoEngine\Core\Module', 'path' => __DIR__.'/Core/Module.php', ), 'api' => array( 'className' => 'ChatHispanoEngine\Api\Module', 'path' => __DIR__.'/Api/Module.php', ), 'login' => array( 'className' => 'ChatHispanoEngine\Login\Module', 'path' => __DIR__.'/Login/Module.php', ), 'oidc' => array( 'className' => 'ChatHispanoEngine\Oidc\Module', 'path' => __DIR__.'/Oidc/Module.php', ), 'web' => array( 'className' => 'ChatHispanoEngine\Web\Module', 'path' => __DIR__.'/Web/Module.php', ), 'backoffice' => array( 'className' => 'ChatHispanoEngine\Backoffice\Module', 'path' => __DIR__.'/Backoffice/Module.php', ), 'movil' => array( 'className' => 'ChatHispanoEngine\Movil\Module', 'path' => __DIR__.'/Movil/Module.php', ), 'regwebexternal' => array( 'className' => 'ChatHispanoEngine\RegWebExternal\Module', 'path' => __DIR__.'/Regwebexternal/Module.php', ), 'cdn' => array( 'className' => 'ChatHispanoEngine\Cdn\Module', 'path' => __DIR__.'/Cdn/Module.php', ), 'shorten' => array( 'className' => 'ChatHispanoEngine\Shorten\Module', 'path' => __DIR__.'/Shorten/Module.php', ), ); static::$DEFAULT_MODULE = $defaultModule; self::$mode = $env; self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt')); define('ENVIRONMENT', self::$mode); if (!defined('PHALCON_MODE')) { $mode = getenv('PHALCON_MODE'); $mode = $mode ? $mode : self::$mode; define('PHALCON_MODE', $mode); } switch (self::getMode()) { case self::MODE_PRODUCTION: case self::MODE_STAGING: error_reporting(0); break; case self::MODE_TEST: case self::MODE_DEVELOPMENT: ini_set('display_errors', 'On'); error_reporting(E_ALL); break; } } /** * Register the services here to make them general or register in * the ModuleDefinition to make them module-specific. */ protected function _registerServices() { $defaultModule = self::$DEFAULT_MODULE; $modules = $this->modules; $config = include __DIR__.'/../config/config.php'; $env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php'; $config->merge($env_config); $di = new \Phalcon\DI\FactoryDefault(); include __DIR__.'/../config/loader.php'; include __DIR__.'/../config/services.php'; include __DIR__.'/../config/routing.php'; $this->setDI($di); } /** * Run the application. */ public function main() { if (static::MODE_PRODUCTION === static::getMode()) { $this->mainProd(); } else { $this->mainDev(); } } private function getRequestUri() { if (!isset($_SERVER)) { return "/"; } if (!is_array($_SERVER)) { return "/"; } if (!isset($_SERVER['REQUEST_URI'])) { return "/"; } return $_SERVER['REQUEST_URI']; } /** * Run the development environment. */ private function mainDev() { (new \Phalcon\Support\Debug())->listen(); $this->_registerServices(); $this->registerModules($this->modules); $response = $this->handle($this->getRequestUri()); $response->send(); } /** * Run the production environment. */ private function mainProd() { try { $this->registerModules($this->modules); $this->_registerServices(); $response = $this->handle($this->getRequestUri()); $response->send(); } catch (\Exception $e) { $logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log'); $msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")"; $msg .= "\n".$e->getTraceAsString(); $logger->process(new \Phalcon\Logger\Item($msg, "error", 100)); $logger->close(); // remove view contents from buffer ob_clean(); $errorCode = 500; $errorView = __DIR__.'/../public/errors/error.html'; if (401 === $e->getCode()) { // 401 UNAUTHORIZED $errorCode = 401; } elseif (403 === $e->getCode()) { // 403 FORBIDDEN $errorCode = 403; } elseif (404 === $e->getCode() || $e instanceof Phalcon\Mvc\View\Exception || $e instanceof Phalcon\Mvc\Dispatcher\Exception) { // 404 NOT FOUND $errorCode = 404; } // Get error view contents. Since we are including the view // file here you can use PHP and local vars inside the error view. ob_start(); include_once $errorView; $contents = ob_get_contents(); ob_end_clean(); // send view to header $response = $this->getDI()->getShared('response'); $response->resetHeaders() ->setStatusCode($errorCode, null) ->setContent($contents) ->send() ; /** * We try to register in MongoDB the error to be able to * track it in backoffice and/or receive emails */ try { $system_log_manager = $this->getDI()->get('system_log_manager'); if ($errorCode == 500) { $system_log_manager->createError([ 'ip' => $_SERVER['SERVER_ADDR'], 'host' => $_SERVER['SERVER_NAME'], 'process' => 'php-fpm', 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ]); } else { $system_log_manager->createWarning([ 'ip' => $_SERVER['SERVER_ADDR'], 'host' => $_SERVER['SERVER_NAME'], 'process' => 'php-fpm', 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ]); } } catch (\Exception $e) { } } } public function slowLog($t) { $config = $this->getDI()->get('config'); $irc_manager = $this->getDI()->get('inspircd_irc_manager'); $server = gethostname() ? gethostname() : 'unknown'; $uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; $msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI'] ."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri; $irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg); } /** * Get the current mode. * * @return string */ public static function getMode() { return self::$mode; } } |
#19 | Application->main /srv/ChatHispanoEngine/releases/94/public/index.php (13) <?php date_default_timezone_set('Europe/Madrid'); require_once __DIR__.'/../vendor/autoload.php'; require_once __DIR__.'/../apps/Application.php'; if (isset($_SERVER['PHALCON_APP'])) { $app = new Application($_SERVER['PHALCON_APP']); } else { $app = new Application('web'); } $app->main(); try { $t = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]; if ($t > 6) { $app->slowLog($t); } } catch (\Exception $e) { } |
Key | Value |
---|---|
_url | /historias/cadiz/2023-03-11/640d256ce8b80261970ad420 |
l | liked |
d | 0 |
c | 1 |
Key | Value |
---|---|
USER | www-data |
HOME | /var/www |
HTTP_CONNECTION | close |
HTTP_X_FORWARDED_FOR | 3.131.94.5 |
HTTP_X_FORWARDED_PROTO | http |
HTTP_COOKIE | CLIENTID=e61017e4-2c45-475c-b0fd-bd542f04ab92; HSESSIONID=cd334e98-fb8a-4bd3-8c24-07f64faeeb48; fikker-KEPi-Z7Xa=BsBSbwRLNOhAxs6UKNM9KWTshGBARUhu |
HTTP_ACCEPT_ENCODING | gzip, br, zstd, deflate |
HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) |
HTTP_ACCEPT | */* |
HTTP_HOST | test.chathispano.com |
DISABLE_ANTEVENIO | 0 |
DISABLE_MOBUSI | 0 |
DISABLE_MASSARIUS | 0 |
DISABLE_RELATEDCONTENT | 0 |
DISABLE_ADSENSE | 0 |
ADS_DEFER | 0 |
PHALCON_APP | web |
CHATHISPANOENGINE_REVISION | development |
CHATHISPANOENGINE_INSTANCE | virtualbox |
SCRIPT_FILENAME | /srv/ChatHispanoEngine/releases/94/public/index.php |
PATH_TRANSLATED | /srv/ChatHispanoEngine/current/public |
PATH_INFO | |
REDIRECT_STATUS | 200 |
SERVER_NAME | test.chathispano.com |
SERVER_PORT | 80 |
SERVER_ADDR | 10.234.61.101 |
REMOTE_USER | |
REMOTE_PORT | 50654 |
REMOTE_ADDR | 10.234.61.52 |
SERVER_SOFTWARE | nginx/1.22.1 |
GATEWAY_INTERFACE | CGI/1.1 |
REQUEST_SCHEME | http |
SERVER_PROTOCOL | HTTP/1.1 |
DOCUMENT_ROOT | /srv/ChatHispanoEngine/releases/94/public |
DOCUMENT_URI | /index.php |
REQUEST_URI | /historias/cadiz/2023-03-11/640d256ce8b80261970ad420?l=liked&d=0&c=1 |
SCRIPT_NAME | /index.php |
CONTENT_LENGTH | |
CONTENT_TYPE | |
REQUEST_METHOD | GET |
QUERY_STRING | _url=/historias/cadiz/2023-03-11/640d256ce8b80261970ad420&l=liked&d=0&c=1 |
FCGI_ROLE | RESPONDER |
PHP_SELF | /index.php |
REQUEST_TIME_FLOAT | 1715737677.1631 |
REQUEST_TIME | 1715737677 |
# | Path |
---|---|
0 | /srv/ChatHispanoEngine/releases/94/public/index.php |
1 | /srv/ChatHispanoEngine/releases/94/vendor/autoload.php |
2 | /srv/ChatHispanoEngine/releases/94/vendor/composer/autoload_real.php |
3 | /srv/ChatHispanoEngine/releases/94/vendor/composer/platform_check.php |
4 | /srv/ChatHispanoEngine/releases/94/vendor/composer/ClassLoader.php |
5 | /srv/ChatHispanoEngine/releases/94/vendor/composer/include_paths.php |
6 | /srv/ChatHispanoEngine/releases/94/vendor/composer/autoload_static.php |
7 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/amp/lib/functions.php |
8 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/amp/lib/Internal/functions.php |
9 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-mbstring/bootstrap.php |
10 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-mbstring/bootstrap80.php |
11 | /srv/ChatHispanoEngine/releases/94/vendor/react/promise/src/functions_include.php |
12 | /srv/ChatHispanoEngine/releases/94/vendor/react/promise/src/functions.php |
13 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/byte-stream/lib/functions.php |
14 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-ctype/bootstrap.php |
15 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-ctype/bootstrap80.php |
16 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-intl-grapheme/bootstrap.php |
17 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-intl-normalizer/bootstrap.php |
18 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php |
19 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-php80/bootstrap.php |
20 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/string/Resources/functions.php |
21 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/process/lib/functions.php |
22 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/serialization/src/functions.php |
23 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/sync/src/functions.php |
24 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/sync/src/ConcurrentIterator/functions.php |
25 | /srv/ChatHispanoEngine/releases/94/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php |
26 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/var-dumper/Resources/functions/dump.php |
27 | /srv/ChatHispanoEngine/releases/94/vendor/daverandom/libdns/src/functions.php |
28 | /srv/ChatHispanoEngine/releases/94/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php |
29 | /srv/ChatHispanoEngine/releases/94/vendor/psy/psysh/src/functions.php |
30 | /srv/ChatHispanoEngine/releases/94/vendor/symfony/polyfill-php81/bootstrap.php |
31 | /srv/ChatHispanoEngine/releases/94/vendor/amphp/dns/lib/functions.php |
32 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/functions.php |
33 | /srv/ChatHispanoEngine/releases/94/vendor/swiftmailer/swiftmailer/lib/swift_required.php |
34 | /srv/ChatHispanoEngine/releases/94/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php |
35 | /srv/ChatHispanoEngine/releases/94/apps/Application.php |
36 | /srv/ChatHispanoEngine/releases/94/config/config.php |
37 | /srv/ChatHispanoEngine/releases/94/config/config_staging.php |
38 | /srv/ChatHispanoEngine/releases/94/config/loader.php |
39 | /srv/ChatHispanoEngine/releases/94/config/services.php |
40 | /srv/ChatHispanoEngine/releases/94/config/managers.php |
41 | /srv/ChatHispanoEngine/releases/94/config/routing.php |
42 | /srv/ChatHispanoEngine/releases/94/apps/Web/config/routing.php |
43 | /srv/ChatHispanoEngine/releases/94/apps/Web/Module.php |
44 | /srv/ChatHispanoEngine/releases/94/apps/Web/config/config.php |
45 | /srv/ChatHispanoEngine/releases/94/apps/Web/config/services.php |
46 | /srv/ChatHispanoEngine/releases/94/apps/Web/config/managers.php |
47 | /srv/ChatHispanoEngine/releases/94/apps/Web/Controllers/StoriesController.php |
48 | /srv/ChatHispanoEngine/releases/94/apps/Web/Controllers/BaseController.php |
49 | /srv/ChatHispanoEngine/releases/94/apps/Core/Controllers/BaseController.php |
50 | /srv/ChatHispanoEngine/releases/94/vendor/iwalkalone/translator/src/iwalkalone/Translator.php |
51 | /srv/ChatHispanoEngine/releases/94/apps/Web/Auth/Auth.php |
52 | /srv/ChatHispanoEngine/releases/94/apps/Core/Managers/InspIRCd/GlineManager.php |
53 | /srv/ChatHispanoEngine/releases/94/apps/Core/Models/InspIRCd/Gline.php |
54 | /srv/ChatHispanoEngine/releases/94/apps/Core/Models/BaseCollection.php |
55 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Client.php |
56 | /srv/ChatHispanoEngine/releases/94/vendor/jean85/pretty-package-versions/src/PrettyVersions.php |
57 | /srv/ChatHispanoEngine/releases/94/vendor/composer/InstalledVersions.php |
58 | /srv/ChatHispanoEngine/releases/94/vendor/composer/installed.php |
59 | /srv/ChatHispanoEngine/releases/94/vendor/jean85/pretty-package-versions/src/Version.php |
60 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Database.php |
61 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Collection.php |
62 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Operation/FindOne.php |
63 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Operation/Executable.php |
64 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Operation/Explainable.php |
65 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Operation/Find.php |
66 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Model/BSONArray.php |
67 | /srv/ChatHispanoEngine/releases/94/vendor/mongodb/mongodb/src/Model/BSONDocument.php |
68 | /srv/ChatHispanoEngine/releases/94/apps/Core/Managers/InspIRCd/ChannelManager.php |
69 | /srv/ChatHispanoEngine/releases/94/apps/Core/Models/Channel/Datasheet.php |
Memory | |
---|---|
Usage | 4194304 |