/** * Normalize local disk-based ABSOLUTE path. * @param string $path * @return string */ public static function diskFullPath($path) { $path = self::diskPath($path); if (!Str::startsWith(root, $path)) { $path = root . DIRECTORY_SEPARATOR . ltrim($path, '\\/'); } return $path; }
/** * Fast redirect in web environment * @param string $to * @param bool $full */ public function redirect($to, $full = false) { $to = trim($to, '/'); if (false === $full && !Str::startsWith(App::$Alias->baseUrl, $to)) { $to = App::$Alias->baseUrl . '/' . $to; } $redirect = new FoundationRedirect($to); $redirect->send(); exit('Redirecting to ' . $to . ' ...'); }
/** * Get internalization based on called controller * @param string $text * @param array $params * @return string */ public function translate($text, array $params = []) { $index = null; $namespace = 'Apps\\Controller\\' . env_name . '\\'; foreach (@debug_backtrace() as $caller) { if (isset($caller['class']) && Str::startsWith($namespace, $caller['class'])) { $index = Str::sub((string) $caller['class'], Str::length($namespace)); } } return $this->get($index, $text, $params); }
/** * Build full URL link from URI string, if REQUEST data is not available (console, cron, etc) * @param string $uri * @param string|null $lang * @return string */ public static function standaloneUrl($uri, $lang = null) { /** @var array $configs */ $configs = \App::$Properties->getAll('default'); $httpHost = $configs['baseProto'] . '://' . $configs['baseDomain']; if ($configs['basePath'] !== '/') { $httpHost .= $configs['basePath'] . '/'; } // check if is this is URI not URL if (!Str::startsWith($httpHost, $uri)) { // check if lang is defined in URI or define it if ($lang !== null && $configs['multiLanguage'] && !Str::startsWith($lang, $uri)) { $uri = $lang . '/' . ltrim($uri, '/'); } // add basic httpHost data $uri = rtrim($httpHost, '/') . '/' . ltrim($uri, '/'); } return $uri; }
/** * Try to recursive validate field by defined rules and set result to model properties if validation is successful passed * @param string|array $field_name * @param string $filter_name * @param mixed $filter_argv * @return bool * @throws SyntaxException */ public function validateRecursive($field_name, $filter_name, $filter_argv = null) { // check if we got it from form defined request method if (App::$Request->getMethod() !== $this->_sendMethod) { return false; } // get field value from user input data $field_value = $this->getFieldValue($field_name); $check = false; // maybe no filter required? if ($filter_name === 'used') { $check = true; } elseif (Str::contains('::', $filter_name)) { // sounds like a callback class::method::method // string to array via delimiter :: $callbackArray = explode('::', $filter_name); // first item is a class name $class = array_shift($callbackArray); // last item its a function $method = array_pop($callbackArray); // left any items? maybe post-static callbacks? if (count($callbackArray) > 0) { foreach ($callbackArray as $obj) { if (Str::startsWith('$', $obj) && property_exists($class, ltrim($obj, '$'))) { // sounds like a variable $obj = ltrim($obj, '$'); // trim variable symbol '$' $class = $class::${$obj}; // make magic :) } elseif (method_exists($class, $obj)) { // maybe its a function? $class = $class::$obj; // call function } else { throw new SyntaxException('Filter callback execution failed: ' . $filter_name); } } } // check is endpoint method exist if (method_exists($class, $method)) { $check = @$class::$method($field_value, $filter_argv); } else { throw new SyntaxException('Filter callback execution failed: ' . $filter_name); } } elseif (method_exists('Ffcms\\Core\\Filter\\Native', $filter_name)) { // only full namespace\class path based :( if ($filter_argv != null) { $check = Native::$filter_name($field_value, $filter_argv); } else { $check = Native::$filter_name($field_value); } } else { throw new SyntaxException('Filter "' . $filter_name . '" is not exist'); } if ($check !== true) { // switch only on fail check. $this->_badAttr[] = $field_name; } else { $field_set_name = $field_name; // prevent array-type setting if (Str::contains('.', $field_set_name)) { $field_set_name = strstr($field_set_name, '.', true); } if (property_exists($this, $field_set_name)) { if ($field_name !== $field_set_name) { // array-based property $dot_path = trim(strstr($field_name, '.'), '.'); // prevent throws any exceptions for null and false objects if (!Obj::isArray($this->{$field_set_name})) { $this->{$field_set_name} = []; } // use dot-data provider to compile output array $dotData = new DotData($this->{$field_set_name}); $dotData->set($dot_path, $field_value); // todo: check me!!! Here can be bug of fail parsing dots and passing path-value // export data from dot-data lib to model property $this->{$field_set_name} = $dotData->export(); } else { // just single property $this->{$field_name} = $field_value; // refresh model property's from post data } } } return $check; }
/** * Save changes in database */ public function save() { $this->_content->title = $this->title; $this->_content->text = $this->text; $this->_content->path = $this->path; $this->_content->category_id = $this->categoryId; $this->_content->author_id = $this->authorId; $this->_content->display = $this->display; $this->_content->meta_title = $this->metaTitle; $this->_content->meta_keywords = $this->metaKeywords; $this->_content->meta_description = $this->metaDescription; $this->_content->source = $this->source; // check if rating is changed if ((int) $this->addRating !== 0) { $this->_content->rating += (int) $this->addRating; } // check if special comment hash is exist if ($this->_new || Str::length($this->_content->comment_hash) < 32) { $this->_content->comment_hash = $this->generateCommentHash(); } // check if date is updated if (!Str::likeEmpty($this->createdAt) && !Str::startsWith('0000', Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP))) { $this->_content->created_at = Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP); } // save poster data $posterPath = '/upload/gallery/' . $this->galleryFreeId . '/orig/' . $this->poster; if (File::exist($posterPath)) { $this->_content->poster = $this->poster; } // get temporary gallery id $tmpGalleryId = $this->galleryFreeId; // save row $this->_content->save(); // update tags data in special table (relation: content->content_tags = oneToMany) ContentTag::where('content_id', '=', $this->_content->id)->delete(); $insertData = []; foreach ($this->metaKeywords as $lang => $keys) { // split keywords to tag array $tags = explode(',', $keys); foreach ($tags as $tag) { // cleanup tag from white spaces $tag = trim($tag); // prepare data to insert if (Str::length($tag) > 0) { $insertData[] = ['content_id' => $this->_content->id, 'lang' => $lang, 'tag' => $tag]; } } } // insert tags ContentTag::insert($insertData); // move files if ($tmpGalleryId !== $this->_content->id) { Directory::rename('/upload/gallery/' . $tmpGalleryId, $this->_content->id); } }
/** * Build link with active definition in listing * @param Dom $dom * @param array $item * @param bool $orderActiveLink * @return string */ private static function buildLink($dom, $item, $orderActiveLink = false) { // set default link data - text and properties $text = self::applyEscape($item['text'], $item['html'], $item['!secure']); $properties = $item['property']; // try to parse link format for controller/action definition (must be array: 'main/index' to ['main/index']) if (!Obj::isArray($item['link']) && !Str::startsWith('http', $item['link']) && !Str::startsWith('#', $item['link'])) { $item['link'] = [$item['link']]; } // if its a controller/action definition try to work with active class if (Obj::isArray($item['link'])) { // check if css class for active item is defined if (!isset($item['activeClass'])) { $item['activeClass'] = 'active'; } // check if element is active on current URI if (self::isCurrentLink($item['link'], $item['activeOn'], $orderActiveLink) === true) { $properties['class'] = Str::concat(' ', $item['activeClass'], $properties['class']); } } // set href source for link $item['linkProperty']['href'] = self::convertLink($item['link']); // build output <li@params><a @params>@text</li> return $dom->li(function () use($dom, $text, $item) { return $dom->a(function () use($text) { return $text; }, $item['linkProperty']); }, $properties); }
/** * Show custom code library link * @param string $type - js or css allowed * @return array|null|string */ public function showCodeLink($type) { $items = App::$Alias->getCustomLibraryArray($type); // check if custom library available if (null === $items || !Obj::isArray($items) || count($items) < 1) { return null; } $output = []; foreach ($items as $item) { $item = trim($item, '/'); if (!Str::startsWith(App::$Alias->scriptUrl, $item) && !Str::startsWith('http', $item)) { // is local without proto and domain $item = App::$Alias->scriptUrl . '/' . $item; } $output[] = $item; } $clear = array_unique($output); $output = null; foreach ($clear as $row) { if ($type === 'css') { $output .= '<link rel="stylesheet" type="text/css" href="' . $row . '">' . "\n"; } elseif ($type === 'js') { $output .= '<script src="' . $row . '"></script>' . "\n"; } } // unset used App::$Alias->unsetCustomLibrary($type); return $output; }
?> </h2> <div class="table-responsive"> <table class="table table-striped"> <tr> <td><?php echo __('Join date'); ?> </td> <td><?php echo Date::convertToDatetime($user->created_at, Date::FORMAT_TO_DAY); ?> </td> </tr> <?php if ($user->getProfile()->birthday !== null && !Str::startsWith('0000-', $user->getProfile()->birthday)) { ?> <tr> <td><?php echo __('Birthday'); ?> </td> <td> <?php echo Url::link(['profile/index', 'born', Date::convertToDatetime($user->getProfile()->birthday, 'Y')], Date::convertToDatetime($user->getProfile()->birthday, Date::FORMAT_TO_DAY)); ?> </td> </tr> <?php } ?>
/** * Prepare dynamic static links from object configurations as anonymous functions * @throws NativeException */ private function dynamicStaticLinks() { /** @var array $objects */ $objects = App::$Properties->getAll('object'); if (!Obj::isArray($objects)) { throw new NativeException('Object configurations is not loaded: /Private/Config/Object.php'); } // each all objects as service_name => service_instance() foreach ($objects as $name => $instance) { // check if definition of object is exist and services list contains it or is null to auto build if (property_exists(get_called_class(), $name) && $instance instanceof \Closure && (isset($this->_services[$name]) || $this->_services === null)) { if ($this->_services[$name] === true || $this->_services === null) { // initialize from configs self::${$name} = $instance(); } elseif (is_callable($this->_services[$name])) { // raw initialization from App::run() self::${$name} = $this->_services[$name](); } } elseif (Str::startsWith('_', $name)) { // just anonymous callback without entry-point @call_user_func($instance); } } }
use Ffcms\Core\Helper\Type\Str; use Ffcms\Core\Helper\Url; $this->title = __('Profile list'); $this->breadcrumbs = [Url::to('main/index') => __('Main'), Url::to('application/index') => __('Applications'), __('Profile')]; ?> <?php echo $this->render('profile/_tabs'); ?> <h1><?php echo __('Profile list'); ?> </h1> <hr /> <?php $items = []; foreach ($records as $profile) { $items[] = [['text' => $profile->id], ['text' => $profile->User()->login . '/' . $profile->User()->email], ['text' => $profile->nick], ['text' => Str::startsWith('0000-', $profile->birthday) ? __('None') : Date::convertToDatetime($profile->birthday)], ['text' => ($profile->rating > 0 ? '+' : null) . $profile->rating], ['text' => Url::link(['profile/update', $profile->id], '<i class="fa fa-pencil fa-lg"></i> ') . Url::link(['user/delete', $profile->User()->id], '<i class="fa fa-trash-o fa-lg"></i>'), 'html' => true, 'property' => ['class' => 'text-center']]]; } ?> <?php echo Table::display(['table' => ['class' => 'table table-bordered'], 'thead' => ['titles' => [['text' => 'id'], ['text' => 'login/email'], ['text' => __('Nickname')], ['text' => __('Birthday')], ['text' => __('Rating')], ['text' => __('Actions')]]], 'tbody' => ['items' => $items]]); ?> <div class="text-center"> <?php echo $pagination->display(['class' => 'pagination pagination-centered']); ?> </div>
?> <h1><?php echo __('Group list'); ?> </h1> <hr /> <?php $items = []; foreach ($records as $role) { $permissions = explode(';', $role->permissions); $permissionsLabel = null; foreach ($permissions as $perm) { $labelMark = null; if (Str::startsWith('admin/', $perm)) { $labelMark = 'label-warning'; } elseif ($perm === 'global/all') { $labelMark = 'label-danger'; } else { $labelMark = 'label-default'; } $permissionsLabel .= '<span class="label ' . $labelMark . '">' . $perm . '</span> '; } $items[] = [['text' => $role->id], ['text' => $role->name], ['text' => $permissionsLabel, 'html' => true], ['text' => Url::link(['user/groupupdate', $role->id], '<i class="fa fa-pencil fa-lg"></i>'), 'property' => ['class' => 'text-center'], 'html' => true]]; } ?> <div class="pull-right"><?php echo Url::link(['user/groupupdate', '0'], __('Add group'), ['class' => 'btn btn-primary']); ?>
/** * Prepare model attributes from passed objects * @throws ForbiddenException */ public function before() { $this->id = $this->_content->id; $this->title = $this->_content->getLocaled('title'); $this->text = $this->_content->getLocaled('text'); // check if title and text are exists if (Str::length($this->title) < 1 || Str::length($this->text) < 1) { throw new ForbiddenException(); } // get meta data $this->metaTitle = $this->_content->getLocaled('meta_title'); if (Str::likeEmpty($this->metaTitle)) { $this->metaTitle = $this->title; } $this->metaDescription = $this->_content->getLocaled('meta_description'); $tmpKeywords = $this->_content->getLocaled('meta_keywords'); $this->metaKeywords = explode(',', $tmpKeywords); // set content date, category data $this->createDate = Date::humanize($this->_content->created_at); $this->catName = $this->_category->getLocaled('title'); $this->catPath = $this->_category->path; // set user data if (App::$User->isExist($this->_content->author_id)) { $this->authorId = $this->_content->author_id; $profile = App::$User->identity($this->authorId)->getProfile(); $this->authorName = $profile->getNickname(); } $this->source = $this->_content->source; $this->views = $this->_content->views + 1; // check for dependence, add '' for general cat, ex: general/depend1/depend2/.../depend-n $catNestingArray = Arr::merge([0 => ''], explode('/', $this->catPath)); if ($catNestingArray > 1) { // latest element its a current nesting level, lets cleanup it array_pop($catNestingArray); $catNestingPath = null; foreach ($catNestingArray as $cPath) { $catNestingPath .= $cPath; // try to find category by path in db $record = ContentCategory::getByPath($catNestingPath); if ($record !== null && $record->count() > 0) { // if founded - add to nesting data $this->catNesting[] = ['name' => $record->getLocaled('title'), 'path' => $record->path]; } if (!Str::likeEmpty($catNestingPath)) { $catNestingPath .= '/'; } } } // build array of category nesting level $this->catNesting[] = ['name' => $this->catName, 'path' => $this->catPath]; // get gallery images and poster data $galleryPath = '/upload/gallery/' . $this->_content->id; // check if gallery folder is exist if (Directory::exist($galleryPath)) { $originImages = File::listFiles($galleryPath . '/orig/', ['.jpg', '.png', '.gif', '.jpeg', '.bmp', '.webp'], true); // generate poster data if (Arr::in($this->_content->poster, $originImages)) { // original poster $posterName = $this->_content->poster; $this->posterFull = $galleryPath . '/orig/' . $posterName; if (!File::exist($this->posterFull)) { $this->posterFull = null; } // thumb poster $posterSplit = explode('.', $posterName); array_pop($posterSplit); $posterCleanName = implode('.', $posterSplit); $this->posterThumb = $galleryPath . '/thumb/' . $posterCleanName . '.jpg'; if (!File::exist($this->posterThumb)) { $this->posterThumb = null; } } // generate full gallery foreach ($originImages as $image) { $imageSplit = explode('.', $image); array_pop($imageSplit); $imageClearName = implode('.', $imageSplit); // skip image used in poster if (Str::startsWith($imageClearName, $this->_content->poster)) { continue; } $thumbPath = $galleryPath . '/thumb/' . $imageClearName . '.jpg'; if (File::exist($thumbPath)) { $this->galleryItems[$thumbPath] = $galleryPath . '/orig/' . $image; } } } // set rating data $this->rating = $this->_content->rating; $ignoredRate = App::$Session->get('content.rate.ignore'); $this->canRate = true; if (Obj::isArray($ignoredRate) && Arr::in((string) $this->id, $ignoredRate)) { $this->canRate = false; } if (!App::$User->isAuth()) { $this->canRate = false; } elseif ($this->authorId === App::$User->identity()->getId()) { $this->canRate = false; } // update views count $this->_content->views += 1; $this->_content->save(); }
/** * Convert link-binding type to classic link with security filter * @param string|array $uri * @return string */ public static function convertLink($uri) { $link = App::$Alias->baseUrl . '/'; if (Obj::isArray($uri)) { $link .= Url::buildPathway($uri); } elseif (Str::startsWith('http', $uri)) { $link = self::nohtml($uri); } elseif (Str::startsWith('#', $uri)) { // allow pass #part $link = self::nohtml($uri); } else { $link .= self::nohtml(trim($uri, '/')); } return $link; }
/** * Download file from $url and save it into $path * @param string $url * @param string $path * @return bool */ public static function saveFromUrl($url, $path) { if (!filter_var($url, FILTER_VALIDATE_URL) || !function_exists('curl_init')) { return false; } $path = Normalize::diskFullPath($path); // check if upload directory is exists $dir = dirname($path); if (!Directory::exist($dir)) { Directory::create($dir); } // initialize stream resource $stream = @fopen($path, 'w'); // initialize curl & set required options, target url, destination save stream $curl = \curl_init(); \curl_setopt($curl, CURLOPT_URL, $url); if (Str::startsWith('https', $url)) { \curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); \curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); } \curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); \curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); \curl_setopt($curl, CURLOPT_HEADER, 0); \curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322'); \curl_setopt($curl, CURLOPT_FAILONERROR, true); \curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); \curl_setopt($curl, CURLOPT_AUTOREFERER, true); \curl_setopt($curl, CURLOPT_TIMEOUT, 10); // set destination file path \curl_setopt($curl, CURLOPT_FILE, $stream); \curl_exec($curl); \curl_close($curl); fclose($stream); return true; }
/** * Get pathway as string * @return string */ public function getPathInfo() { $route = $this->languageInPath ? Str::sub(parent::getPathInfo(), Str::length($this->language) + 1) : parent::getPathInfo(); if (!Str::startsWith('/', $route)) { $route = '/' . $route; } return $route; }
/** * Cleanup all public model properties */ public function clearProperties() { foreach ($this as $property => $value) { if (!Str::startsWith('_', $property)) { $this->{$property} = null; } } }