/** * Decode string $data and get value by key * @param $data * @param string $key * @return string|array|null */ public static function getDecoded($data, $key) { if (!Obj::isArray($data)) { $data = self::decode($data); } return $data === false ? null : $data[$key]; }
/** * Run cron task. Attention - this method is too 'fat' to run from any app's * @return array|null */ public function run() { // check if cron instances is defined if (!isset($this->configs['instances']) || !Obj::isArray($this->configs['instances'])) { return null; } // get timestamp $time = time(); $log = []; // each every one instance foreach ($this->configs['instances'] as $callback => $delay) { if ((int) $this->configs['log'][$callback] + $delay <= $time) { // prepare cron initializing list($class, $method) = explode('::', $callback); if (class_exists($class) && method_exists($class, $method)) { // make static callback forward_static_call([$class, $method]); $log[] = $callback; } // update log information $this->configs['log'][$callback] = $time + $delay; } } // write updated configs App::$Properties->writeConfig('Cron', $this->configs); return $log; }
/** * Build <input type="checkbox" checked {$properties} /> response * {@inheritDoc} * @see \Ffcms\Core\Helper\HTML\Form\iField::make() * @throws \Ffcms\Core\Exception\NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function make() { // check if options is defined $options = $this->properties['options']; if (!Obj::isIterable($options)) { throw new SyntaxException('Options for field ' . self::nohtml($this->name) . ' is not iterable'); } unset($this->properties['options']); // set field type $this->properties['type'] = 'checkbox'; // set this field as array html dom object $this->properties['name'] .= '[]'; unset($this->properties['value'], $this->properties['id']); $build = null; foreach ($options as $opt) { // check if this is active element if (Obj::isArray($this->value) && Arr::in($opt, $this->value)) { $this->properties['checked'] = null; } else { unset($this->properties['checked']); // remove checked if it setted before } $this->properties['value'] = $opt; // apply structured checkboxes style for each item $build .= App::$View->render('native/form/multi_checkboxes_list', ['item' => self::buildSingleTag('input', $this->properties) . self::nohtml($opt)]); } return $build; }
/** * Scan available permissions and write to cfg file * @return string */ public function actionBuildperms() { // default permissions $permissions = ['global/write', 'global/modify', 'global/file', 'global/all']; // admin controllers $AdminAppControllers = '/Apps/Controller/Admin/'; // scan directory $scan = File::listFiles($AdminAppControllers, ['.php']); foreach ($scan as $file) { $className = Str::firstIn(Str::lastIn($file, DIRECTORY_SEPARATOR, true), '.'); // read as plain text $byte = File::read($file); preg_match_all('/public function action(\\w*?)\\(/', $byte, $matches); // matches[0] contains all methods ;) if (Obj::isArray($matches[1]) && count($matches[1]) > 0) { foreach ($matches[1] as $perm) { $permissions[] = 'Admin/' . $className . '/' . $perm; } } } // prepare save string $stringSave = "<?php \n\nreturn " . var_export($permissions, true) . ';'; File::write('/Private/Config/Permissions.php', $stringSave); return 'Permissions configuration is successful updated! Founded permissions: ' . count($permissions); }
/** * Delete user row from database * @param int $id * @return string * @throws \Ffcms\Core\Exception\SyntaxException * @throws \Ffcms\Core\Exception\NativeException * @throws NotFoundException */ public function actionDelete($id = null) { // check if id is passed or get data from GET as array ids if ($id === 0 || (int) $id < 1) { $ids = $this->request->query->get('selected'); if (Obj::isArray($ids) && Arr::onlyNumericValues($ids)) { $id = $ids; } else { throw new NotFoundException('Bad conditions'); } } else { $id = [$id]; } // initialize delete model $model = new FormUserDelete($id); // check if users is found if ($model->users === null) { throw new NotFoundException(__('Users are not found')); } // check if delete is submited if ($model->send() && $model->validate()) { $model->delete(); App::$Session->getFlashBag()->add('success', __('Users and them data are successful removed')); $this->response->redirect('user/index'); } // set view response return $this->view->render('user_delete', ['model' => $model]); }
/** * Upload files from ckeditor * @param string $type * @return string * @throws NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function actionUpload($type) { /** @var $loadFile \Symfony\Component\HttpFoundation\File\UploadedFile */ $loadFile = App::$Request->files->get('upload'); if ($loadFile === null || $loadFile->getError() !== 0) { return $this->errorResponse(__('File upload failed')); } // get file extension $fileExt = '.' . $loadFile->guessExtension(); // check if this request type is allowed if ($this->allowedExt[$type] === null || !Obj::isArray($this->allowedExt[$type])) { throw new NativeException('Hack attempt'); } // check if this file extension is allowed to upload if (!Arr::in($fileExt, $this->allowedExt[$type])) { return $this->errorResponse(__('This file type is not allowed to upload')); } $date = Date::convertToDatetime(time(), 'd-m-Y'); // create file hash based on name-size $fileNewName = App::$Security->simpleHash($loadFile->getFilename() . $loadFile->getSize()) . $fileExt; $savePath = Normalize::diskFullPath('/upload/' . $type . '/' . $date); // save file from tmp to regular $loadFile->move($savePath, $fileNewName); // generate URI of uploaded file $url = '/upload/' . $type . '/' . $date . '/' . $fileNewName; return App::$View->render('editor/load_success', ['callbackId' => (int) App::$Request->query->get('CKEditorFuncNum'), 'url' => $url], __DIR__); }
/** * Get sitemap index files info as array * @return array */ public function getInfo() { if (!Obj::isArray($this->info)) { return []; } return $this->info; }
public static function widget(array $params = null) { self::$class = get_called_class(); // check if class exist if (!class_exists(self::$class)) { return 'Error: Widget is not founded: ' . self::$class; } // init class and pass properties $object = new self::$class(); if (Obj::isArray($params) && count($params) > 0) { foreach ($params as $property => $value) { if (property_exists($object, $property)) { $object->{$property} = $value; } } } // prepare output $out = null; try { $object->init(); $out = $object->display(); } catch (\Exception $e) { throw $e; } return $out; }
public function makeTag($name, $value = null, $properties = null) { // check if properties is passed well if ($properties !== null && !Obj::isArray($properties)) { throw new SyntaxException('Property must be passed as array or null! Field: ' . $name); } // add properties to autovalidation by js (properties passed by ref) $this->validatorProperties($name, $properties); // prepare properties name and id to autobuild $this->globalProperties($name, $value, $properties); // initialize build model depend of current type switch ($this->type) { case static::TYPE_TEXT: // for <input type="text"> $builder = new TextField($properties, $name); return $builder->make(); case static::TYPE_CHECKBOX: $builder = new CheckboxField($properties, $name, $value); return $builder->make(); case static::TYPE_PASSWORD: $builder = new PasswordField($properties, $name); return $builder->make(); case static::TYPE_EMAIL: $builder = new EmailField($properties, $name); return $builder->make(); case static::TYPE_SELECT: $builder = new SelectField($properties, $name, $value); return $builder->make(); case static::TYPE_TEXTAREA: $builder = new TextareaField($properties, $name, $value); return $builder->make(); case static::TYPE_MULTI_CHECKBOXES: $builder = new MultiCheckboxField($properties, $name, $value); return $builder->make(); case static::TYPE_CAPTCHA: $builder = new CaptchaField($properties, $name); return $builder->make(); case static::TYPE_FILE: $builder = new FileField($properties, $name); return $builder->make(); case static::TYPE_HIDDEN: $builder = new HiddenField($properties, $name, $value); return $builder->make(); case static::TYPE_DIV_FAKE: $builder = new DivFakeField($properties, $name, $value); return $builder->make(); case static::TYPE_MULTISELECT: $builder = new MultiSelectField($properties, $name, $value); return $builder->make(); case static::TYPE_RADIO: $builder = new RadioField($properties, $name, $value); return $builder->make(); } // if field is unknown type add notification in debugbar if (App::$Debug !== null) { App::$Debug->addMessage('Field with name [' . App::$Security->strip_tags($name) . '] have unknown type [' . $this->type . ']', 'error'); } return 'No data: ' . App::$Security->strip_tags($name); }
/** * Get all permissions as array * @return array * @throws SyntaxException */ public function getAllPermissions() { $p = App::$Properties->getAll('permissions'); if ($p === false || !Obj::isArray($p)) { throw new SyntaxException('User permissions settings is not founded: /Private/Config/Permissions.php'); } return $p; }
/** * 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; } }
/** * EntityContentSearch constructor. Pass search terms (query string) to model and used items to skip it by id. * @param $terms * @param int|array $skipIds */ public function __construct($terms, $skipIds = 0) { $this->_terms = App::$Security->strip_tags(trim($terms, ' ')); if (Obj::isLikeInt($skipIds)) { $this->_skip = [$skipIds]; } elseif (Obj::isArray($skipIds)) { $this->_skip = $skipIds; } parent::__construct(); }
/** * 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}); }
/** * Set property values from configurations */ public function before() { $properties = App::$Properties->getAll(); if ($properties === false || !Obj::isArray($properties)) { return; } // set default values foreach (App::$Properties->getAll() as $key => $value) { if (property_exists($this, $key)) { $this->{$key} = $value; } } }
/** * Build xml output and save it into sitemap folder * @param string $uniqueName * @return bool * @throws \Ffcms\Core\Exception\NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function save($uniqueName) { // check if data exists if ($this->data === null || !Obj::isArray($this->data)) { return false; } // list data each every language, render xml output and write into file foreach ($this->data as $lang => $items) { $xml = App::$View->render('native/sitemap_urlset', ['items' => $items]); File::write(EntityIndexList::INDEX_PATH . '/' . $uniqueName . '.' . $lang . '.xml', $xml); } return true; }
/** * Build console controllers. * php console.php Controller/Action index */ public static function run() { global $argv; $output = null; if (!Obj::isArray($argv) || Str::likeEmpty($argv[1])) { $output = 'Console command is unknown! Type "console main/help" to get help guide'; } else { $controller_action = $argv[1]; $arrInput = explode('/', $controller_action); $controller = ucfirst(strtolower($arrInput[0])); $action = ucfirst(strtolower($arrInput[1])); if ($action == null) { $action = 'Index'; } // set action and id $action = 'action' . $action; $id = null; if (isset($argv[2])) { $id = $argv[2]; } try { $controller_path = '/Apps/Controller/' . env_name . '/' . $controller . '.php'; if (file_exists(root . $controller_path) && is_readable(root . $controller_path)) { include_once root . $controller_path; $cname = 'Apps\\Controller\\' . env_name . '\\' . $controller; if (class_exists($cname)) { $load = new $cname(); if (method_exists($cname, $action)) { if ($id !== null) { $output = @$load->{$action}($id); } else { $output = @$load->{$action}(); } } else { throw new NativeException('Method ' . $action . '() not founded in ' . $cname . ' in file {root}' . $controller_path); } unset($load); } else { throw new NativeException('Namespace\\Class - ' . $cname . ' not founded in {root}' . $controller_path); } } else { throw new NativeException('Controller not founded: {root}' . $controller_path); } } catch (NativeException $e) { $e->display($e->getMessage()); } } return self::$Output->write($output); }
/** * Add ckeditor library's to lazyload * @return null */ public function display() { App::$Alias->setCustomLibrary('js', $this->baseUrl . '/ckeditor.js'); App::$Alias->setCustomLibrary('js', $this->baseUrl . '/adapters/jquery.js'); $jsInitializeCode = "\$('.{$this->targetClass}').ckeditor({"; $jsInitializeCode .= "language: '{$this->language}', customConfig: '{$this->config}.js', "; if ($this->jsConfig !== null && Obj::isArray($this->jsConfig)) { foreach ($this->jsConfig as $obj => $value) { $jsInitializeCode .= $obj . ": '" . $value . "', "; } } $jsInitializeCode .= "});"; App::$Alias->addPlainCode('js', $jsInitializeCode); return null; }
/** * 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; }
/** * String html tags and escape quotes * @param string|array $html * @param boolean $escapeQuotes * @return string|array|null */ public function strip_tags($html, $escapeQuotes = true) { // recursive usage if (Obj::isArray($html)) { foreach ($html as $key => $value) { $html[$key] = $this->strip_tags($value, $escapeQuotes); } return $html; } $text = strip_tags($html); if ($escapeQuotes) { $text = $this->escapeQuotes($text); } return $text; }
/** * Display language switcher as html or get builded result as array * @return array|null|string */ public function display() { // prevent loading on disabled multi-language property if ($this->multiLangEnabled !== true) { return null; } // check if languages is defined and count more then 1 if (!Obj::isArray($this->langs) || count($this->langs) < 2) { return null; } // build output items for listing $items = []; foreach ($this->langs as $lang) { $items[] = ['type' => 'link', 'link' => App::$Alias->baseUrlNoLang . '/' . $lang . App::$Request->getPathInfo(), 'text' => '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="flag flag-' . $lang . '" alt="' . $lang . '"/>', 'html' => true, '!secure' => true]; } if ($this->onlyArrayItems) { return $items; } return Listing::display(['type' => 'ul', 'property' => $this->css, 'items' => $items]); }
/** * Find latest release in github API and get required info */ private function findLatestVersion() { // get remote api with json response $gitJson = File::getFromUrl(static::API_LATEST_RELEASE); if ($gitJson === null || $gitJson === false) { return; } // parse api response to model attributes $git = json_decode($gitJson, true); $this->lastVersion = $git['tag_name']; // get download url to full compiled distributive (uploaded to each release as .zip archive, placed in release.assets) $download = null; if (Obj::isArray($git['assets'])) { foreach ($git['assets'] as $asset) { if ($asset['content_type'] === 'application/zip' && $asset['state'] === 'uploaded') { $download = $asset['browser_download_url']; } } } $this->lastInfo = ['name' => $git['name'], 'created_at' => Date::convertToDatetime($git['published_at'], Date::FORMAT_TO_HOUR), 'download_url' => $download]; }
/** * Initialize event on happend * @return mixed */ public function run() { // dynamicly parse input params $args = func_get_args(); if (count($args) < 1) { return false; } // get event name $eventName = array_shift($args); // get event args as array if passed $eventArgs = @array_shift($args); // if event is registered if (isset($this->events[$eventName]) && Obj::isArray($this->events[$eventName])) { foreach ($this->events[$eventName] as $callback) { // call anonymous function with args if passed return call_user_func_array($callback, $eventArgs); } } // set to post runned actions $this->runned[$eventName] = $eventArgs; return false; }
/** * Get sorted by relevance search response. Method return result as array: [relevance => [title, snippet, uri, date], ...] * @return array */ public function getRelevanceSortedResult() { $result = []; // each every content type foreach ($this->results as $type => $items) { if (!Obj::isArray($items)) { continue; } // each every element foreach ($items as $item) { /** @var AbstractSearchResult $item */ // build unique relevance. Problem: returned relevance from query is integer // and can be duplicated. So, we add random complex float value and make it string to sort in feature $uniqueRelevance = (string) ($item->getRelevance() + mt_rand(0, 999) / 10000); // build response $result[$uniqueRelevance] = ['title' => $item->getTitle(), 'snippet' => $item->getSnippet(), 'uri' => $item->getUri(), 'date' => $item->getDate()]; } } // sort output by relevance krsort($result); // return result as array return $result; }
/** * Build <select @properties>@optionsDOM</select> container * {@inheritDoc} * @see \Ffcms\Core\Helper\HTML\Form\iField::make() */ public function make() { // check if options is defined $options = $this->properties['options']; $optionsKey = (bool) $this->properties['optionsKey']; if (!Obj::isIterable($options)) { throw new SyntaxException('Options for field ' . self::nohtml($this->name) . ' is not iterable'); } unset($this->properties['options']); // set global field type $this->properties['type'] = 'select'; // add multiple element $this->properties['multiple'] = null; $this->properties['name'] .= '[]'; unset($this->properties['value'], $this->properties['options'], $this->properties['optionsKey']); // build options as HTML DOM element: <option @value>@text</option> $optionsDOM = null; foreach ($options as $val => $text) { // check if options key is value $optionProperty = null; if ($optionsKey === true) { $optionProperty['value'] = $val; // check if current element is active if (Obj::isArray($this->value) && Arr::in((string) $val, $this->value)) { $optionProperty['selected'] = 'selected'; } } else { if (Obj::isArray($this->value) && Arr::in((string) $text, $this->value)) { $optionProperty['selected'] = 'selected'; } } $optionsDOM .= self::buildContainerTag('option', $optionProperty, $text); } // build <select @properties>@optionsDOM</select> return self::buildContainerTag('select', $this->properties, $optionsDOM, true); }
require_once root . '/Loader/Autoload.php'; // make fast-access alias \App::$Object // class_alias('Ffcms\Core\App', 'App'); class App extends Ffcms\Core\App { } /** * Alias for translate function for fast usage. Example: __('Welcome my friend') * @param string $text * @param array $params * @return string */ function __($text, array $params = []) { return \App::$Translate->translate($text, $params); } try { // prepare to run $app = \App::factory(['Database' => true, 'User' => true, 'Mailer' => true, 'Cache' => true]); $cronManager = new \Ffcms\Core\Managers\CronManager(\App::$Properties->getAll('Cron')); $logs = $cronManager->run(); if (PHP_SAPI === 'cli') { if ($logs !== null && \Ffcms\Core\Helper\Type\Obj::isArray($logs) && count($logs) > 0) { echo 'Run cron tasks: ' . PHP_EOL . implode(PHP_EOL, $logs); } else { echo 'No tasks runned'; } } } catch (Exception $e) { (new \Ffcms\Core\Exception\NativeException($e->getMessage()))->display(); }
/** * Set GET param to property array * @param int|string $page_id * @return array */ protected function setUrlPage($page_id) { $url = $this->url; switch (count($url)) { // check nulls if not set case 1: // only controller/action is defined $url[1] = null; $url[2] = null; break; case 2: $url[2] = null; break; } // add page param if > 0 if ((int) $page_id > 0) { // merge with ?page if query is not empty if (Obj::isArray($url[3])) { $url[3] = Arr::merge($url[3], ['page' => $page_id]); } else { // just set ?page=$page_id $url[3] = ['page' => $page_id]; } } return $url; }
/** * Get field value from input POST/GET/AJAX data with defined security level (html - safe html, !secure = fully unescaped) * @param string $field_name * @return array|null|string * @throws \InvalidArgumentException */ private function getFieldValue($field_name) { // get type of input data (where we must look it up) $inputType = Str::lowerCase($this->_sendMethod); $filterType = 'text'; // get declared field sources and types $sources = $this->sources(); $types = $this->types(); // validate sources for current field if (Obj::isArray($sources) && array_key_exists($field_name, $sources)) { $inputType = Str::lowerCase($sources[$field_name]); } if (Obj::isArray($types)) { // check if field is array-nested element by dots and use first element as general $filterField = $field_name; // check if field_name is dot-separated array and use general part if (Str::contains('.', $field_name)) { $filterField = Str::firstIn($field_name, '.'); } if (array_key_exists($filterField, $types)) { $filterType = Str::lowerCase($types[$filterField]); } } // get clear field value $field_value = $this->getRequest($field_name, $inputType); // apply security filter for input data if ($inputType !== 'file') { if ($filterType === 'html') { $field_value = App::$Security->secureHtml($field_value); } elseif ($filterType !== '!secure') { $field_value = App::$Security->strip_tags($field_value); } } return $field_value; }
<span class="spaced hidden-xs"><i class="fa fa-comments"></i> <a href="<?php echo \App::$Alias->baseUrl . $item['uri']; ?> #comments-list"><?php echo __('Comments'); ?> : <span itemprop="commentCount" id="comment-count-<?php echo $item['id']; ?> ">0</span></a> </span> <span class="pull-right"> <?php if ((int) $catConfigs['showTags'] === 1 && $item['tags'] !== null && Obj::isArray($item['tags'])) { ?> <span class="spaced"><i class="fa fa-tags hidden-xs"></i> <?php foreach ($item['tags'] as $tag) { echo Url::link(['content/tag', $tag], $tag, ['class' => 'label label-default']) . " "; } ?> </span> <meta itemprop="keywords" content="<?php implode(',', $item['tags']); ?> "> <?php } ?>
/** * Create <a></a> block link * @param string|array $to * @param string $name * @param array|null $property * @return string */ public static function link($to, $name, array $property = null) { $compile_property = self::applyProperty($property); if (!Obj::isArray($to)) { // callback magic (: $to = [$to]; } // call Url::to(args) $callbackTo = call_user_func_array([__NAMESPACE__ . '\\Url', 'to'], $to); return '<a href="' . $callbackTo . '"' . $compile_property . '>' . $name . '</a>'; }
/** * Get property by key of current category * @param string $key * @return bool|string|null */ public function getProperty($key) { $properties = $this->configs; // check if properties is defined if (!Obj::isArray($properties) || !array_key_exists($key, $properties)) { return false; } return $properties[$key]; }