/** * Finally delete content item */ public function make() { // remove gallery files if exists foreach ($this->_records->get() as $record) { $galleryPath = '/upload/gallery/' . (int) $record->id; if (Directory::exist($galleryPath)) { Directory::remove($galleryPath); } } // finally remove from db $this->_records->forceDelete(); }
/** * Get available themes for environment * @param $env_name * @return array */ public function getAvailableThemes($env_name) { $path = root . '/Apps/View/' . $env_name . '/'; if (!Directory::exist($path)) { return []; } $scan = Directory::scan($path); $response = []; foreach ($scan as $object) { $response[] = substr(strrchr($object, '/'), 1); } return $response; }
/** * Try to find sitemap indexes in storage directory * @throws SyntaxException */ public function before() { if (!Directory::exist(static::INDEX_PATH)) { throw new SyntaxException(__('Directory %dir% for sitemaps is not exists', ['dir' => static::INDEX_PATH])); } $scan = File::listFiles(static::INDEX_PATH, ['.xml'], true); if (Obj::isArray($scan)) { foreach ($scan as $file) { if ($this->_lang !== null && !Str::contains('.' . $this->_lang, $file)) { continue; } $this->files[] = static::INDEX_PATH . '/' . $file; } } }
/** * Get default server information and prepare chmod info */ public function before() { $this->phpVersion = phpversion(); $this->pdo = extension_loaded('pdo'); $this->gd = extension_loaded('gd') && function_exists('gd_info'); // autoload is disabled, lets get chmod file & dirs from console app data File::inc('/Apps/Controller/Console/Main.php'); $this->_chmodDirs = Main::$installDirs; // for each file or directory in list - check permissions foreach ($this->_chmodDirs as $object) { if (Str::endsWith('.php', $object)) { // sounds like a file $this->chmodCheck[$object] = File::exist($object) && File::writable($object); } else { $this->chmodCheck[$object] = Directory::exist($object) && Directory::writable($object); } } }
/** * Lets construct viewer * @throws NativeException */ public function __construct() { $this->lang = App::$Request->getLanguage(); // get theme config and build full path $themeConfig = App::$Properties->get('theme'); $this->themePath = root . DIRECTORY_SEPARATOR . 'Apps' . DIRECTORY_SEPARATOR . 'View' . DIRECTORY_SEPARATOR . env_name; if (isset($themeConfig[env_name]) && Str::length($themeConfig[env_name]) > 0) { $this->themePath .= DIRECTORY_SEPARATOR . $themeConfig[env_name]; } else { $this->themePath .= DIRECTORY_SEPARATOR . 'default'; } // check if theme is available if (!Directory::exist($this->themePath)) { throw new NativeException('Apps theme is not founded: ' . Str::replace(root, null, $this->themePath)); } // get input args and build class properties $args = func_get_args(); $this->path = array_shift($args); $this->params = array_shift($args); $this->sourcePath = array_shift($args); }
/** * Index page of admin dashboard * @return string * @throws \Ffcms\Core\Exception\SyntaxException * @throws \Ffcms\Core\Exception\NativeException */ public function actionIndex() { // cache some data $rootSize = App::$Cache->get('root.size'); if ($rootSize === null) { $rootSize = round(Directory::getSize('/') / (1024 * 1000), 2) . ' mb'; App::$Cache->set('root.size', $rootSize, 86400); // 24 hours caching = 60 * 60 * 24 } $loadAvg = App::$Cache->get('load.average'); if ($loadAvg === null) { $loadAvg = Environment::loadAverage(); App::$Cache->set('load.average', $loadAvg, 60 * 5); // 5 min cache } // prepare system statistic $stats = ['ff_version' => Version::VERSION . ' (' . Version::DATE . ')', 'php_version' => Environment::phpVersion() . ' (' . Environment::phpSAPI() . ')', 'os_name' => Environment::osName(), 'database_name' => App::$Database->connection()->getDatabaseName() . ' (' . App::$Database->connection()->getDriverName() . ')', 'file_size' => $rootSize, 'load_avg' => $loadAvg]; // check directory chmods and other environment features $model = new EntityCheck(); // render view output return $this->view->render('index', ['stats' => $stats, 'check' => $model]); }
/** * 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); } }
/** * Find all bootatble instances and set it to object map */ public function compileBootableClasses() { // list app root's foreach ($this->appRoots as $app) { $app .= '/Apps/Controller/' . env_name; $files = File::listFiles($app, ['.php'], true); foreach ($files as $file) { // define full class name with namespace $class = 'Apps\\Controller\\' . env_name . '\\' . Str::cleanExtension($file); // check if class exists (must be loaded over autoloader), boot method exist and this is controller instanceof if (class_exists($class) && method_exists($class, 'boot') && is_a($class, 'Ffcms\\Core\\Arch\\Controller', true)) { $this->objects[] = $class; } } } // list widget root's foreach ($this->widgetRoots as $widget) { $widget .= '/Widgets/' . env_name; // widgets are packed in directory, classname should be the same with root directory name $dirs = Directory::scan($widget, GLOB_ONLYDIR, true); if (!Obj::isArray($dirs)) { continue; } foreach ($dirs as $instance) { $class = 'Widgets\\' . env_name . '\\' . $instance . '\\' . $instance; if (class_exists($class) && method_exists($class, 'boot') && is_a($class, 'Ffcms\\Core\\Arch\\Widget', true)) { $this->objects[] = $class; } } } }
public function createObject($name, $type) { $singleName = false; if (!Str::contains('/', $name)) { if ($type === 'ActiveRecord') { $singleName = true; } else { $this->message = 'Command dosn\'t contains valid name. Example: Front/SomeForm, Admin/SomePkg/SomeInput'; return false; } } $objectDirPath = null; $objectNamespace = null; $objectName = null; $objectTemplate = null; if ($singleName) { $objectDirPath = root . '/Apps/' . $type . '/'; $objectNamespace = 'Apps\\' . $type; $objectName = ucfirst($name); } else { $split = explode('/', $name); $workground = ucfirst(strtolower(array_shift($split))); $objectName = ucfirst(array_pop($split)); $subName = false; if (count($split) > 0) { // some sub-namespace / folder path foreach ($split as $part) { if (Str::length($part) > 0) { $subName[] = ucfirst(strtolower($part)); } } } if ($type === 'Widget') { $objectDirPath = root . '/Widgets/' . $workground; $objectNamespace = 'Widgets\\' . $workground; } else { $objectDirPath = root . '/Apps/' . $type . '/' . $workground; $objectNamespace = 'Apps\\' . $type . '\\' . $workground; } if (false !== $subName) { $objectDirPath .= '/' . implode('/', $subName); $objectNamespace .= '\\' . implode('\\', $subName); } // try to find workground-based controller if (File::exist('/Private/Carcase/' . $workground . '/' . $type . '.tphp')) { $objectTemplate = File::read('/Private/Carcase/' . $workground . '/' . $type . '.tphp'); } } if (!Directory::exist($objectDirPath) && !Directory::create($objectDirPath)) { $this->message = 'Directory could not be created: ' . $objectDirPath; return false; } if ($objectTemplate === null) { $objectTemplate = File::read('/Private/Carcase/' . $type . '.tphp'); if (false === $objectTemplate) { $this->message = 'Php template file is not founded: /Private/Carcase/' . $type . '.tphp'; return false; } } $objectContent = Str::replace(['%namespace%', '%name%'], [$objectNamespace, $objectName], $objectTemplate); $objectFullPath = $objectDirPath . '/' . $objectName . '.php'; if (File::exist($objectFullPath)) { $this->message = $type . ' is always exist: ' . $objectFullPath; return false; } File::write($objectFullPath, $objectContent); $this->message = $type . ' template was created: [' . $objectName . '] in path: ' . Str::replace(root, '', $objectDirPath); return true; }
/** * 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(); }
/** * Get available languages in the filesystem * @return array */ public function getAvailableLangs() { $langs = ['en']; $scan = Directory::scan(root . '/I18n/' . env_name . '/', GLOB_ONLYDIR, true); foreach ($scan as $row) { $langs[] = trim($row, '/'); } return $langs; }
/** * Save input data to database */ public function make() { // save data to db $this->_record->title = $this->title; $this->_record->text = $this->text; $this->_record->path = $this->path; $this->_record->category_id = (int) $this->categoryId; $this->_record->display = 0; // set to premoderation $this->_record->author_id = (int) $this->authorId; if ($this->_new === true) { $this->_record->comment_hash = $this->generateCommentHash(); } $this->_record->save(); // work with poster data if ($this->poster !== null) { // lets move poster from tmp to gallery $originDir = '/upload/gallery/' . $this->_record->id . '/orig/'; $thumbDir = '/upload/gallery/' . $this->_record->id . '/thumb/'; if (!Directory::exist($originDir)) { Directory::create($originDir); } if (!Directory::exist($thumbDir)) { Directory::create($thumbDir); } $fileName = App::$Security->simpleHash($this->poster->getClientOriginalName() . $this->poster->getSize()); $newFullName = $fileName . '.' . $this->poster->guessExtension(); // move poster to upload gallery directory $this->poster->move(Normalize::diskFullPath($originDir), $newFullName); // initialize image resizer $thumb = new Image(); $thumb->setCacheDir(root . '/Private/Cache/images'); // open original file, resize it and save $thumbSaveName = Normalize::diskFullPath($thumbDir) . '/' . $fileName . '.jpg'; $thumb->open(Normalize::diskFullPath($originDir) . DIRECTORY_SEPARATOR . $newFullName)->cropResize($this->_configs['galleryResize'])->save($thumbSaveName, 'jpg', 90); $thumb = null; // update poster in database $this->_record->poster = $newFullName; $this->_record->save(); } }
/** * Console installation * @return string * @throws NativeException */ public function actionInstall() { if (File::exist('/Private/Install/install.lock')) { throw new NativeException('Installation is locked! Please delete /Private/Install/install.lock'); } echo Console::$Output->writeHeader('License start'); echo File::read('/LICENSE') . PHP_EOL; echo Console::$Output->writeHeader('License end'); $config = Console::$Properties->get('database'); $newConfig = []; // creating default directory's foreach (self::$installDirs as $obj) { // looks like a directory if (!Str::contains('.', $obj)) { Directory::create($obj, 0777); } } echo Console::$Output->write('Upload and private directories are successful created!'); // set chmods echo $this->actionChmod(); // database config from input echo Console::$Output->writeHeader('Database connection configuration'); echo 'Driver(default:' . $config['driver'] . '):'; $dbDriver = Console::$Input->read(); if (Arr::in($dbDriver, ['mysql', 'pgsql', 'sqlite'])) { $newConfig['driver'] = $dbDriver; } // for sqlite its would be a path echo 'Host(default:' . $config['host'] . '):'; $dbHost = Console::$Input->read(); if (!Str::likeEmpty($dbHost)) { $newConfig['host'] = $dbHost; } echo 'Database name(default:' . $config['database'] . '):'; $dbName = Console::$Input->read(); if (!Str::likeEmpty($dbName)) { $newConfig['database'] = $dbName; } echo 'User(default:' . $config['username'] . '):'; $dbUser = Console::$Input->read(); if (!Str::likeEmpty($dbUser)) { $newConfig['username'] = $dbUser; } echo 'Password(default:' . $config['password'] . '):'; $dbPwd = Console::$Input->read(); if (!Str::likeEmpty($dbPwd)) { $newConfig['password'] = $dbPwd; } echo 'Table prefix(default:' . $config['prefix'] . '):'; $dbPrefix = Console::$Input->read(); if (!Str::likeEmpty($dbPrefix)) { $newConfig['prefix'] = $dbPrefix; } // merge configs and add new connection to db pull $dbConfigs = Arr::merge($config, $newConfig); Console::$Database->addConnection($dbConfigs, 'install'); try { Console::$Database->connection('install')->getDatabaseName(); } catch (\Exception $e) { return 'Testing database connection is failed! Run installer again and pass tested connection data! Log: ' . $e->getMessage(); } // autoload isn't work here include root . '/Apps/Controller/Console/Db.php'; // import db data $dbController = new DbController(); echo $dbController->actionImportAll('install'); // add system info about current install version $system = new System(); $system->setConnection('install'); $system->var = 'version'; $system->data = Version::VERSION; $system->save(); // set website send from email from input $emailConfig = Console::$Properties->get('adminEmail'); echo 'Website sendFrom email(default: ' . $emailConfig . '):'; $email = Console::$Input->read(); if (!Str::isEmail($email)) { $email = $emailConfig; } // set base domain echo 'Website base domain name(ex. ffcms.org):'; $baseDomain = Console::$Input->read(); if (Str::likeEmpty($baseDomain)) { $baseDomain = Console::$Properties->get('baseDomain'); } // generate other configuration data and security salt, key's and other echo Console::$Output->writeHeader('Writing configurations'); /** @var array $allCfg */ $allCfg = Console::$Properties->getAll('default'); $allCfg['database'] = $dbConfigs; $allCfg['adminEmail'] = $email; $allCfg['baseDomain'] = $baseDomain; echo Console::$Output->write('Generate password salt for BLOWFISH crypt'); $allCfg['passwordSalt'] = '$2a$07$' . Str::randomLatinNumeric(mt_rand(21, 30)) . '$'; echo Console::$Output->write('Generate security cookies for debug panel'); $allCfg['debug']['cookie']['key'] = 'fdebug_' . Str::randomLatinNumeric(mt_rand(8, 32)); $allCfg['debug']['cookie']['value'] = Str::randomLatinNumeric(mt_rand(32, 128)); // write config data $writeCfg = Console::$Properties->writeConfig('default', $allCfg); if ($writeCfg !== true) { return 'File /Private/Config/Default.php is unavailable to write data!'; } File::write('/Private/Install/install.lock', 'Install is locked'); return 'Configuration done! FFCMS 3 is successful installed! Visit your website. You can add administrator using command php console.php db/adduser'; }
/** * 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; }
/** * Show gallery images from upload directory * @param int $id * @return string * @throws NotFoundException * @throws NativeException */ public function actionGallerylist($id) { // check if id is passed if (Str::likeEmpty($id)) { throw new NativeException('Wrong input data'); } // check if user have permission to access there if (!App::$User->isAuth() || !App::$User->identity()->getRole()->can('global/file')) { throw new NativeException('Permission denied'); } $thumbDir = Normalize::diskFullPath('/upload/gallery/' . $id . '/orig/'); if (!Directory::exist($thumbDir)) { throw new NotFoundException('Nothing found'); } $files = Directory::scan($thumbDir, null, true); if ($files === false || !Obj::isArray($files) || count($files) < 1) { throw new NotFoundException('Nothing found'); } $output = []; foreach ($files as $file) { $fileExt = Str::lastIn($file, '.'); $fileName = Str::sub($file, 0, -Str::length($fileExt)); $output[] = ['thumbnailUrl' => '/upload/gallery/' . $id . '/thumb/' . $fileName . '.jpg', 'url' => '/upload/gallery/' . $id . '/orig/' . $file, 'name' => $file, 'size' => File::size('/upload/gallery/' . $id . '/orig/' . $file)]; } $this->setJsonHeader(); return json_encode(['status' => 1, 'files' => $output]); }