/** * Make snippet from text or html-text content. * @param string $text * @param int $length * @return string */ public static function snippet($text, $length = 150) { // check if valid string is passed if (!Obj::isString($text)) { return null; } $breakerPos = mb_strpos($text, self::WYSIWYG_BREAK_HTML, null, 'UTF-8'); // offset is founded, try to split preview from full text if ($breakerPos !== false) { $text = Str::sub($text, 0, $breakerPos); } else { // page breaker is not founded, lets get a fun ;D // find first paragraph ending $breakerPos = mb_strpos($text, '</p>', null, 'UTF-8'); // no paragraph's ? lets try to get <br[\/|*]> if ($breakerPos === false) { $breakerPos = mb_strpos($text, '<br', null, 'UTF-8'); } else { // add length('</p>') $breakerPos += 4; } // cut text from position caret before </p> (+4 symbols to save item as valid) if ($breakerPos !== false) { $text = Str::sub($text, 0, $breakerPos); } } // if breaker position is still undefined - lets make 'text cut' for defined length and remove all html tags if ($breakerPos === false) { $text = strip_tags($text); $text = self::cut($text, 0, $length); } return $text; }
/** * Form constructor. Build form based on model properties * @param Model $model * @param array|null $property * @param array|null $layerFiles * @throws SyntaxException */ public function __construct($model, array $property = null, array $layerFiles = null) { // prevent white-screen locks when model is not passed or passed wrong if (!$model instanceof Model) { throw new SyntaxException('Bad model type passed in form builder. Check for init: new Form()'); } $this->model = $model; $this->name = $model->getFormName(); // check if passed custom layer file if (Obj::isArray($layerFiles) && count($layerFiles) > 0) { foreach (array_keys(static::$structLayer) as $type) { if (isset($layerFiles[$type]) && Obj::isString($layerFiles[$type])) { static::$structLayer[$type] = $layerFiles[$type]; } } } // set model submit method $property['method'] = $this->model->getSubmitMethod(); $property['id'] = $this->name; // define form id // if action is not defined - define it if (Str::likeEmpty($property['action'])) { $property['action'] = App::$Request->getFullUrl(); } // set property global for this form $this->formProperty = $property; }
/** * Set global variable from key=>value array (key = varname) * @param array $array */ public function setGlobalArray(array $array) { if (!Obj::isArray($array)) { return; } foreach ($array as $var => $value) { $this->globalVars[$var] = Obj::isString($value) ? App::$Security->strip_tags($value) : $value; } }
/** * Prepare conditions to build content list * @throws NotFoundException */ public function before() { // check length of passed terms if (!Obj::isString($this->_terms) || Str::length($this->_terms) < self::MIN_QUERY_LENGTH) { throw new NotFoundException(__('Search terms is too short')); } // lets make active record building $this->_records = ContentEntity::whereNotIn('id', $this->_skip)->search($this->_terms)->take(self::MAX_ITEMS)->get(); $this->buildContent(); parent::before(); }
/** * Special function for locale stored attributes under serialization. * @param string $attribute * @return array|null|string */ public function getLocaled($attribute) { // if always decoded if (Obj::isArray($this->{$attribute})) { return $this->{$attribute}[App::$Request->getLanguage()]; } if (!Obj::isString($attribute) || Str::likeEmpty($this->{$attribute})) { return null; } return Serialize::getDecodeLocale($this->{$attribute}); }
/** * Add message into debug bar * @param string $m * @param string $type * @throws \DebugBar\DebugBarException */ public function addMessage($m, $type = 'info') { if (!Obj::isString($m) || !Obj::isString($type)) { return; } $m = App::$Security->secureHtml($m); $mCollector = $this->bar->getCollector('messages'); if (method_exists($mCollector, $type)) { $this->bar->getCollector('messages')->{$type}($m); } }
/** * Get single row by defined type and sys_name with query caching * @param string $type * @param string|array $sys_name * @return mixed|null * @throws SyntaxException */ public static function getItem($type, $sys_name) { foreach (self::all() as $object) { if ($object->type === $type) { //&& $object->sys_name === $sys_name) { if (Obj::isArray($sys_name) && Arr::in($object->sys_name, $sys_name)) { // many different app name - maybe alias or something else return $object; } elseif (Obj::isString($sys_name) && $object->sys_name === $sys_name) { return $object; } } } return null; }
/** * Check if user with $login is exist * @param string $login * @return bool */ public static function isLoginExist($login) { if (!Obj::isString($login) || Str::length($login) < 1) { return false; } return self::where('login', '=', $login)->count() > 0; }
/** * Build pathway from array $to. Example: ['controller/action', 'id', 'add', ['get' => 'value'], '#anchor'] * @param array $to * @param bool $encode * @return string|null */ public static function buildPathway(array $to = null, $encode = true) { // if empty passed - let show main page if ($to === null) { return null; } $response = Str::lowerCase(trim($to[0], '/')); // controller/action list($controller, $action) = explode('/', $response); $routing = App::$Properties->getAll('Routing'); // sounds like dynamic callback if (Str::startsWith('@', $controller)) { $controller = trim($controller, '@'); // search callback in properties if (isset($routing['Callback'][env_name]) && Arr::in($controller, $routing['Callback'][env_name])) { $pathInject = array_search($controller, $routing['Callback'][env_name]); // if path is founded - lets set source if ($pathInject !== false) { $controller = Str::lowerCase($pathInject); } } // if controller still looks like path injection - define last entity like controller name if (Str::contains('\\', $controller)) { $controller = Str::lastIn($controller, '\\', true); } $response = $controller . '/' . $action; } // check if controller and action is defined if (Str::likeEmpty($controller) || Str::likeEmpty($action)) { return null; } // id is defined? if (isset($to[1]) && !Str::likeEmpty($to[1])) { $response .= '/' . self::safeUri($to[1], $encode); } // add param is defined? if (isset($to[2]) && !Str::likeEmpty($to[2])) { $response .= '/' . self::safeUri($to[2], $encode); } // try to find static alias if (isset($routing['Alias'][env_name]) && Arr::in('/' . $response, $routing['Alias'][env_name])) { $pathAlias = array_search('/' . $response, $routing['Alias'][env_name]); if ($pathAlias !== false) { $response = Str::lowerCase(trim($pathAlias, '/')); } } // parse get attributes if (isset($to[3]) && Obj::isArray($to[3]) && count($to[3]) > 0) { // check if anchor bindig is exist $anchor = false; if (isset($to[3]['#']) && Obj::isString($to[3]['#']) && Str::startsWith('#', $to[3]['#'])) { $anchor = $to[3]['#']; unset($to[3]['#']); } $queryString = http_build_query($to[3]); if (Str::length($queryString) > 0) { $response .= '?' . http_build_query($to[3]); } if ($anchor !== false) { $response .= $anchor; } } // parse anchor link part #item-related-id-1 if (isset($to[4]) && Obj::isString($to[4]) && Str::startsWith('#', $to[4])) { $response .= $to[4]; } return $response; }
<?php use Ffcms\Core\Helper\Type\Obj; use Ffcms\Core\Helper\Type\Str; $code = \App::$Properties->get('gaTrackId'); if (!Obj::isString($code) || Str::length($code) < 3) { return null; } ?> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', '<?php echo $code; ?> ', 'auto'); ga('send', 'pageview'); </script>
/** * Filter ['object', 'string'] * @param $object * @return bool */ public static function string($object) { return Obj::isString($object); }
/** * Build bootstrap navbar * @param array $elements * @return NULL|string */ public static function display($elements) { // check if elements passed well if (!Obj::isArray($elements) || count($elements['items']) < 1) { return null; } // set default bootstrap properties if not defined $elements['property']['class'] = Str::concat(' ', 'nav', $elements['property']['class']); $elements['nav']['class'] = Str::concat(' ', 'navbar', $elements['nav']['class']); if ($elements['container'] === null) { $elements['container'] = 'container-fluid'; } // set mobile collapse id for toggle $mobCollapseId = $elements['collapseId']; if (Str::likeEmpty($mobCollapseId)) { $mobCollapseId = Str::randomLatin(mt_rand(6, 12)) . mt_rand(1, 99); } // set element id for toggle $ulId = 1; // prepare array's for left, right and static elements $itemsLeft = []; $itemsRight = []; $itemsStatic = null; foreach ($elements['items'] as $item) { if (Obj::isString($item)) { // sounds like a static object w/o render request $itemsStatic .= $item; } else { if ($item['type'] === 'dropdown') { // build bootstrap dropdown properties $item['dropdown'] = ['class' => 'dropdown-toggle', 'data-toggle' => 'dropdown', 'href' => '#']; $item['property']['class'] = Str::concat(' ', 'dropdown', $item['property']['class']); } else { $item['type'] = 'link'; } // set item with position if ($item['position'] !== null && $item['position'] === 'right') { // right position item $itemsRight[] = $item; } else { // left pos item $itemsLeft[] = $item; } } } // build html dom for left and right elements $leftBuild = null; $rightBuild = null; if (count($itemsLeft) > 0) { $mainElemLeft = $elements['property']; // todo: fix me!! $mainElemLeft['id'] .= $ulId; $ulId++; $leftBuild = Listing::display(['type' => 'ul', 'property' => $mainElemLeft, 'activeOrder' => $elements['activeOrder'], 'items' => $itemsLeft]); } if (count($itemsRight) > 0) { $mainElemRight = $elements['property']; // todo: fix me!! $mainElemRight['class'] .= ' navbar-right'; $mainElemRight['id'] .= $ulId; $ulId++; $rightBuild = Listing::display(['type' => 'ul', 'property' => $mainElemRight, 'activeOrder' => $elements['activeOrder'], 'items' => $itemsRight]); } // generate output dom of bootstrap navbar $dom = new Dom(); $body = $dom->div(function () use($leftBuild, $rightBuild, $itemsStatic) { return $leftBuild . $itemsStatic . $rightBuild; }, ['class' => 'collapse navbar-collapse', 'id' => $mobCollapseId]); // drow <nav @properties>@next</nav> return $dom->nav(function () use($dom, $elements, $mobCollapseId, $body) { // drow <div @container>@next</div> return $dom->div(function () use($dom, $elements, $mobCollapseId, $body) { // drow <div @navbar-header>@next</div> $header = $dom->div(function () use($dom, $elements, $mobCollapseId) { // drow <button @collapse>@next</button> $collapseButton = $dom->button(function () use($dom) { $toggleItem = $dom->span(function () { return 'Toggle menu'; }, ['class' => 'sr-only']); $toggleIcon = null; for ($i = 0; $i < 3; $i++) { $toggleIcon .= $dom->span(function () { return null; }, ['class' => 'icon-bar']); } return $toggleItem . $toggleIcon; }, ['type' => 'button', 'class' => 'navbar-toggle collapsed', 'data-toggle' => 'collapse', 'data-target' => '#' . $mobCollapseId]); // drow <div @brand>@brandtext<?div> $brand = null; if (isset($elements['brand'])) { if (isset($elements['brand']['link'])) { $brand = Url::link($elements['brand']['link'], $elements['brand']['text'], ['class' => 'navbar-brand']); } else { $brand = (new Dom())->span(function () use($elements) { return $elements['brand']['text']; }, ['class' => 'navbar-brand']); } } return $collapseButton . $brand; }, ['class' => 'navbar-header']); // return header and body concat return $header . $body; }, $elements['container']); }, $elements['nav']); }
/** * Get locale data from input array or serialized string * @param array|string $input * @param string|null $lang * @param string|null $default * @return string|null */ public function getLocaleText($input, $lang = null, $default = null) { // define language if empty if ($lang === null) { $lang = App::$Request->getLanguage(); } // unserialize from string to array if (Obj::isString($input)) { $input = Serialize::decode($input); } if (Obj::isArray($input) && array_key_exists($lang, $input)) { return $input[$lang]; } return $default; }
/** * Crypt password secure with Blow fish crypt algo (defined in salt) * Blow fish crypt example: crypt('somedata', '$2a$07$usesomesillystringfor$'), where $2a$07$ - definition of algo, * usesomesillystringfor - is salt (must be 21 or more chars), $ - end caret. Output: $2a$07$usesomesillystringfor.sUeCOxyFvckc3xgq1Kzqq90gLrrIVjq * @param string $password * @param string|null $salt * @return string */ public static function password_hash($password, $salt = null) { if ($salt === null || !Obj::isString($salt) || Str::length($salt) < 1) { $salt = App::$Properties->get('passwordSalt'); } return crypt($password, $salt); }
/** * Add new post answer from AJAX post * @param int $postId * @return string * @throws ForbiddenException * @throws NativeException */ public function actionSendwallanswer($postId) { // not auth? what are you doing there? ;) if (!App::$User->isAuth()) { throw new ForbiddenException('Auth required'); } // no post id? wtf you doing man! if (!Obj::isLikeInt($postId) || $postId < 1) { throw new NativeException('Wrong input data'); } // get current(sender) user object $viewer = App::$User->identity(); // get message from post and validate minlength $message = $this->request->get('message'); $message = App::$Security->strip_tags($message); if (!Obj::isString($message) || Str::length($message) < 3) { throw new ForbiddenException('Wrong input data'); } // try to find this post $wallPost = WallPost::where('id', '=', $postId); if ($wallPost->count() < 1) { throw new NativeException('Wrong input data'); } $wallRow = $wallPost->first(); $target_id = $wallRow->target_id; // check if in blacklist if (!Blacklist::check($viewer->id, $target_id)) { throw new ForbiddenException('User is blocked!'); } // check delay between user last post and current $lastAnswer = WallAnswer::where('user_id', '=', App::$User->identity()->getId())->orderBy('created_at', 'DESC')->first(); if (null !== $lastAnswer && false !== $lastAnswer) { $now = time(); $answerTime = Date::convertToTimestamp($lastAnswer->created_at); $cfgs = \Apps\ActiveRecord\App::getConfigs('app', 'Profile'); // hmm, maybe past less then delay required? if ($now - (int) $cfgs['delayBetweenPost'] < $answerTime) { throw new ForbiddenException('Delay between answers not pass'); } } // make new row ;) $answers = new WallAnswer(); $answers->post_id = $postId; $answers->user_id = $viewer->id; $answers->message = $message; $answers->save(); // add notification for target user if ($viewer->id !== $target_id) { $notify = new EntityAddNotification($target_id); $notify->add('/profile/show/' . $target_id . '#wall-post-' . $wallRow->id, EntityAddNotification::MSG_ADD_WALLANSWER, ['snippet' => Text::snippet($message, 50), 'post' => $wallRow->message]); } // send "ok" response $this->setJsonHeader(); return json_encode(['status' => 1, 'message' => 'ok']); }