protected function checkSecurityToken() { /** @var Request $request */ $request = $this->container['request']; $nonce = $request->get->get('nonce'); return isset($nonce) && Utils::verifyNonce($nonce, 'gantry-admin'); }
/** * Save a group */ public function save() { $blueprints = new Blueprints('blueprints://'); $blueprint = $blueprints->get('user/group'); $fields = $blueprint->fields(); self::getGrav()['config']->set("groups.{$this->groupname}", []); foreach ($fields as $field) { if ($field['type'] == 'text') { $value = $field['name']; if (isset($this->items[$value])) { self::getGrav()['config']->set("groups.{$this->groupname}.{$value}", $this->items[$value]); } } if ($field['type'] == 'array') { $value = $field['name']; $arrayValues = Utils::resolve($this->items, $field['name']); if ($arrayValues) { foreach ($arrayValues as $arrayIndex => $arrayValue) { self::getGrav()['config']->set("groups.{$this->groupname}.{$value}.{$arrayIndex}", $arrayValue); } } } } $type = 'groups'; $blueprints = $this->blueprints("config/{$type}"); $obj = new Data(self::getGrav()['config']->get($type), $blueprints); $file = CompiledYamlFile::instance(self::getGrav()['locator']->findResource("config://{$type}.yaml")); $obj->file($file); $obj->save(); }
public function init() { $this->shortcode->getHandlers()->add('fa', function (ShortcodeInterface $sc) { // Load assets if required if ($this->config->get('plugins.shortcode-core.fontawesome.load', false)) { $this->shortcode->addAssets('css', $this->config->get('plugins.shortcode-core.fontawesome.url')); } // Get shortcode content and parameters $str = $sc->getContent(); $icon = $sc->getParameter('icon', false); if (!$icon) { $icon = $sc->getParameter('fa', trim($sc->getParameterAt(0), '=')); } if (!Utils::startsWith($icon, 'fa-')) { $icon = 'fa-' . $icon; } $extras = explode(',', $sc->getParameter('extras', '')); foreach ($extras as $extra) { if (!Utils::startsWith($extra, 'fa-')) { $extra = 'fa-' . $extra; } $icon .= ' ' . $extra; } $output = '<i class="fa ' . $icon . '">' . $str . '</i>'; return $output; }); }
/** * If the admin path matches, initialize the Login plugin configuration and set the admin * as active. */ public function setup() { // Autoloader spl_autoload_register(function ($class) { if (Utils::startsWith($class, 'Grav\\Plugin\\Admin')) { require_once __DIR__ . '/classes/' . strtolower(basename(str_replace("\\", "/", $class))) . '.php'; } }); $route = $this->config->get('plugins.admin.route'); if (!$route) { return; } $this->base = '/' . trim($route, '/'); $this->admin_route = rtrim($this->grav['pages']->base(), '/') . $this->base; $this->uri = $this->grav['uri']; // check for existence of a user account $account_dir = $file_path = $this->grav['locator']->findResource('account://'); $user_check = glob($account_dir . '/*.yaml'); // If no users found, go to register if ($user_check == false || count((array) $user_check) == 0) { if (!$this->isAdminPath()) { $this->grav->redirect($this->admin_route); } $this->template = 'register'; } // Only activate admin if we're inside the admin path. if ($this->isAdminPath()) { $this->active = true; // Set cache based on admin_cache option if (method_exists($this->grav['cache'], 'setEnabled')) { $this->grav['cache']->setEnabled($this->config->get('plugins.admin.cache_enabled')); } } }
/** * Makes a request to the URL by using the preferred method * @param string $uri URL to call * @param array $options An array of parameters for both `curl` and `fopen` * @param callable $callback Either a function or callback in array notation * @return string The response of the request */ public static function get($uri = '', $options = [], $callback = null) { if (!self::isCurlAvailable() && !self::isFopenAvailable()) { throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available'); } // disable time limit if possible to help with slow downloads if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode')) { set_time_limit(0); } $options = array_replace_recursive(self::$defaults, $options); $method = 'get' . ucfirst(strtolower(self::$method)); self::$callback = $callback; return static::$method($uri, $options, $callback); }
private function getContents($fn) { if (Utils::startswith($fn, 'data:')) { $path = $this->grav['locator']->findResource('user://data', true); $fn = ltrim($fn, 'data:'); } else { $path = $this->grav['page']->path(); } $path = $path . DS . $fn; if (file_exists($path)) { return file_get_contents($path); } return null; }
/** * Makes a request to the URL by using the preferred method * * @param string $uri URL to call * @param array $options An array of parameters for both `curl` and `fopen` * @param callable $callback Either a function or callback in array notation * * @return string The response of the request */ public static function get($uri = '', $options = [], $callback = null) { if (!self::isCurlAvailable() && !self::isFopenAvailable()) { throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available'); } // check if this function is available, if so use it to stop any timeouts try { if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode') && function_exists('set_time_limit')) { set_time_limit(0); } } catch (\Exception $e) { } $options = array_replace_recursive(self::$defaults, $options); $method = 'get' . ucfirst(strtolower(self::$method)); self::$callback = $callback; return static::$method($uri, $options, $callback); }
public function filecontent($path) { $path_info = pathinfo($path); $config = Grav::instance()['config']->get('plugins.file-content'); if (in_array($path_info['extension'], $config['allowed_extensions'])) { if (Utils::startsWith($path, '/')) { if ($config['allow_in_grav'] && file_exists(GRAV_ROOT . $path)) { return file_get_contents(GRAV_ROOT . $path); } elseif ($config['allow_in_filesystem'] && file_exists($path)) { return file_get_contents($path); } } else { $page_path = Grav::instance()['page']->path() . '/' . $path; if ($config['allow_in_page'] && file_exists($page_path)) { return file_get_contents($page_path); } } } return $path; }
public function init() { $this->shortcode->getHandlers()->add('ui-animated-text', function (ShortcodeInterface $sc) { // Add assets $this->shortcode->addAssets('css', 'plugin://shortcode-ui/css/ui-atext.css'); $this->shortcode->addAssets('js', 'plugin://shortcode-ui/js/ui-atext.js'); $content = $sc->getContent(); $animation = $sc->getParameter('animation', 'rotate-1'); $words = $sc->getParameter('words', 'cool, funky, fresh'); $visible = $sc->getParameter('visible', 1); if (Utils::contains($content, '%WORDS%')) { $content = explode('%WORDS%', $content); } else { $content = (array) $content; } if (intval($visible) > count($words)) { $visible = 1; } $output = $this->twig->processTemplate('partials/ui-atext.html.twig', ['content' => $content, 'words' => explode(',', $words), 'animation' => $animation, 'element' => $sc->getParameter('element', 'h1'), 'wrapper_extra' => Utils::contains($animation, 'type') ? ' waiting' : '', 'visible' => $visible]); return $output; }); }
/** * @return int|null|void */ protected function serve() { $this->options = $this->input->getOptions(); $this->gpm = new GPM($this->options['force']); $this->displayGPMRelease(); $this->data = $this->gpm->getRepository(); $data = $this->filter($this->data); $climate = new CLImate(); $climate->extend('Grav\\Console\\TerminalObjects\\Table'); if (!$data) { $this->output->writeln('No data was found in the GPM repository stored locally.'); $this->output->writeln('Please try clearing cache and running the <green>bin/gpm index -f</green> command again'); $this->output->writeln('If this doesn\'t work try tweaking your GPM system settings.'); $this->output->writeln(''); $this->output->writeln('For more help go to:'); $this->output->writeln(' -> <yellow>https://learn.getgrav.org/troubleshooting/common-problems#cannot-connect-to-the-gpm</yellow>'); die; } foreach ($data as $type => $packages) { $this->output->writeln("<green>" . strtoupper($type) . "</green> [ " . count($packages) . " ]"); $packages = $this->sort($packages); if (!empty($packages)) { $table = []; $index = 0; foreach ($packages as $slug => $package) { $row = ['Count' => $index++ + 1, 'Name' => "<cyan>" . Utils::truncate($package->name, 20, false, ' ', '...') . "</cyan> ", 'Slug' => $slug, 'Version' => $this->version($package), 'Installed' => $this->installed($package)]; $table[] = $row; } $climate->table($table); } $this->output->writeln(''); } $this->output->writeln('You can either get more informations about a package by typing:'); $this->output->writeln(' <green>' . $this->argv . ' info <cyan><package></cyan></green>'); $this->output->writeln(''); $this->output->writeln('Or you can install a package by typing:'); $this->output->writeln(' <green>' . $this->argv . ' install <cyan><package></cyan></green>'); $this->output->writeln(''); }
/** * Makes a request to the URL by using the preferred method * * @param string $uri URL to call * @param array $options An array of parameters for both `curl` and `fopen` * @param callable $callback Either a function or callback in array notation * * @return string The response of the request */ public static function get($uri = '', $options = [], $callback = null) { if (!self::isCurlAvailable() && !self::isFopenAvailable()) { throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available'); } // check if this function is available, if so use it to stop any timeouts try { if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode') && function_exists('set_time_limit')) { set_time_limit(0); } } catch (\Exception $e) { } $config = Grav::instance()['config']; $overrides = []; // SSL Verify Peer and Proxy Setting $settings = ['method' => $config->get('system.gpm.method', self::$method), 'verify_peer' => $config->get('system.gpm.verify_peer', true), 'proxy_url' => $config->get('system.gpm.proxy_url', $config->get('system.proxy_url', false))]; if (!$settings['verify_peer']) { $overrides = array_replace_recursive([], $overrides, ['curl' => [CURLOPT_SSL_VERIFYPEER => $settings['verify_peer']], 'fopen' => ['ssl' => ['verify_peer' => $settings['verify_peer'], 'verify_peer_name' => $settings['verify_peer']]]]); } // Proxy Setting if ($settings['proxy_url']) { $proxy = parse_url($settings['proxy_url']); $fopen_proxy = ($proxy['scheme'] ?: 'http') . '://' . $proxy['host'] . (isset($proxy['port']) ? ':' . $proxy['port'] : ''); $overrides = array_replace_recursive([], $overrides, ['curl' => [CURLOPT_PROXY => $proxy['host'], CURLOPT_PROXYTYPE => 'HTTP'], 'fopen' => ['proxy' => $fopen_proxy, 'request_fulluri' => true]]); if (isset($proxy['port'])) { $overrides['curl'][CURLOPT_PROXYPORT] = $proxy['port']; } if (isset($proxy['user']) && isset($proxy['pass'])) { $fopen_auth = $auth = base64_encode($proxy['user'] . ':' . $proxy['pass']); $overrides['curl'][CURLOPT_PROXYUSERPWD] = $proxy['user'] . ':' . $proxy['pass']; $overrides['fopen']['header'] = "Proxy-Authorization: Basic {$fopen_auth}"; } } $options = array_replace_recursive(self::$defaults, $options, $overrides); $method = 'get' . ucfirst(strtolower($settings['method'])); self::$callback = $callback; return static::$method($uri, $options, $callback); }
/** * Handle the email to activate the user account. * * @return bool True if the action was performed. */ protected function sendActivationEmail($user) { if (empty($user->email)) { throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.USER_NEEDS_EMAIL_FIELD')); } $token = md5(uniqid(mt_rand(), true)); $expire = time() + 604800; // next week $user->activation_token = $token . '::' . $expire; $user->save(); $param_sep = $this->grav['config']->get('system.param_sep', ':'); $activation_link = $this->grav['base_url_absolute'] . $this->config->get('plugins.login.route_activate') . '/token' . $param_sep . $token . '/username' . $param_sep . $user->username . '/nonce' . $param_sep . Utils::getNonce('user-activation'); $sitename = $this->grav['config']->get('site.title', 'Website'); $subject = $this->grav['language']->translate(['PLUGIN_LOGIN.ACTIVATION_EMAIL_SUBJECT', $sitename]); $content = $this->grav['language']->translate(['PLUGIN_LOGIN.ACTIVATION_EMAIL_BODY', $user->username, $activation_link, $sitename]); $to = $user->email; $sent = LoginUtils::sendEmail($subject, $content, $to); if ($sent < 1) { throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.EMAIL_SENDING_FAILURE')); } return true; }
/** * Recursive function to load & build page relationships. * * @param string $directory * @param Page|null $parent * @return Page * @throws \RuntimeException * @internal */ protected function recurse($directory, Page &$parent = null) { $directory = rtrim($directory, DS); $page = new Page(); /** @var Config $config */ $config = $this->grav['config']; /** @var Language $language */ $language = $this->grav['language']; // stuff to do at root page if ($parent === null) { // Fire event for memory and time consuming plugins... if ($config->get('system.pages.events.page')) { $this->grav->fireEvent('onBuildPagesInitialized'); } } $page->path($directory); if ($parent) { $page->parent($parent); } $page->orderDir($config->get('system.pages.order.dir')); $page->orderBy($config->get('system.pages.order.by')); // Add into instances if (!isset($this->instances[$page->path()])) { $this->instances[$page->path()] = $page; if ($parent && $page->path()) { $this->children[$parent->path()][$page->path()] = array('slug' => $page->slug()); } } else { throw new \RuntimeException('Fatal error when creating page instances.'); } $content_exists = false; $pages_found = glob($directory . '/*' . CONTENT_EXT); $page_extensions = $language->getFallbackPageExtensions(); if ($pages_found) { foreach ($page_extensions as $extension) { foreach ($pages_found as $found) { if (preg_match('/^.*\\/[0-9A-Za-z\\-\\_]+(' . $extension . ')$/', $found)) { $page_found = $found; $page_extension = $extension; break 2; } } } } if ($parent && !empty($page_found)) { $file = new \SplFileInfo($page_found); $page->init($file, $page_extension); $content_exists = true; if ($config->get('system.pages.events.page')) { $this->grav->fireEvent('onPageProcessed', new Event(['page' => $page])); } } // set current modified of page $last_modified = $page->modified(); /** @var \DirectoryIterator $file */ foreach (new \FilesystemIterator($directory) as $file) { $name = $file->getFilename(); // Ignore all hidden files if set. if ($this->ignore_hidden) { if ($name && $name[0] == '.') { continue; } } if ($file->isFile()) { // Update the last modified if it's newer than already found if (!in_array($file->getBasename(), $this->ignore_files) && ($modified = $file->getMTime()) > $last_modified) { $last_modified = $modified; } } elseif ($file->isDir() && !in_array($file->getFilename(), $this->ignore_folders)) { if (!$page->path()) { $page->path($file->getPath()); } $path = $directory . DS . $name; $child = $this->recurse($path, $page); if (Utils::startsWith($name, '_')) { $child->routable(false); } $this->children[$page->path()][$child->path()] = array('slug' => $child->slug()); if ($config->get('system.pages.events.page')) { $this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page])); } } } // Set routability to false if no page found if (!$content_exists) { $page->routable(false); } // Override the modified and ID so that it takes the latest change into account $page->modified($last_modified); $page->id($last_modified . md5($page->filePath())); // Sort based on Defaults or Page Overridden sort order $this->children[$page->path()] = $this->sort($page); return $page; }
/** * Provides the ability to download a file to the browser * * @param $file the full path to the file to be downloaded * @param bool $force_download as opposed to letting browser choose if to download or render */ public static function download($file, $force_download = true) { if (file_exists($file)) { // fire download event self::getGrav()->fireEvent('onBeforeDownload', new Event(['file' => $file])); $file_parts = pathinfo($file); $filesize = filesize($file); // check if this function is available, if so use it to stop any timeouts if (function_exists('set_time_limit')) { set_time_limit(0); } ignore_user_abort(false); if ($force_download) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . $file_parts['basename']); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); } else { header("Content-Type: " . Utils::getMimeType($file_parts['extension'])); } header('Content-Length: ' . $filesize); // 8kb chunks for now $chunk = 8 * 1024; $fh = fopen($file, "rb"); if ($fh === false) { return; } // Repeat reading until EOF while (!feof($fh)) { echo fread($fh, $chunk); ob_flush(); // flush output flush(); } exit; } }
/** * Searches for a list of Packages in the repository * @param array $searches An array of either slugs or names * @return array Array of found Packages * Format: ['total' => int, 'not_found' => array, <found-slugs>] */ public function findPackages($searches = []) { $packages = ['total' => 0, 'not_found' => []]; foreach ($searches as $search) { $repository = ''; // if this is an object, get the search data from the key if (is_object($search)) { $search = (array) $search; $key = key($search); $repository = $search[$key]; $search = $key; } if ($found = $this->findPackage($search)) { // set override respository if provided if ($repository) { $found->override_repository = $repository; } if (!isset($packages[$found->package_type])) { $packages[$found->package_type] = []; } $packages[$found->package_type][$found->slug] = $found; $packages['total']++; } else { // make a best guess at the type based on the repo URL if (Utils::contains($repository, '-theme')) { $type = 'themes'; } else { $type = 'plugins'; } $not_found = new \stdClass(); $not_found->name = Inflector::camelize($search); $not_found->slug = $search; $not_found->package_type = $type; $not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]); $not_found->override_repository = $repository; $packages['not_found'][$search] = $not_found; } } return $packages; }
/** * Return URL to image. * * @param bool $reset * @return string */ public function url($reset = true) { $image_path = self::$grav['locator']->findResource('cache://images', true); $image_dir = self::$grav['locator']->findResource('cache://images', false); $saved_image_path = $this->saveImage(); $output = preg_replace('|^' . preg_quote(GRAV_ROOT) . '|', '', $saved_image_path); if (Utils::startsWith($output, $image_path)) { $output = '/' . $image_dir . preg_replace('|^' . preg_quote($image_path) . '|', '', $output); } if ($reset) { $this->reset(); } return self::$grav['base_url'] . $output . $this->querystring() . $this->urlHash(); }
/** * Build search results. */ public function onPagesInitialized() { $page = $this->grav['page']; // If a page exists merge the configs if ($page) { $this->config->set('plugins.simplesearch', $this->mergeConfig($page)); } /** @var Uri $uri */ $uri = $this->grav['uri']; $query = $uri->param('query') ?: $uri->query('query'); $route = $this->config->get('plugins.simplesearch.route'); // performance check if ($route && $query && $route == $uri->path()) { $this->enable(['onTwigSiteVariables' => ['onTwigSiteVariables', 0]]); } else { return; } $this->query = explode(',', $query); /** @var Taxonomy $taxonomy_map */ $taxonomy_map = $this->grav['taxonomy']; $taxonomies = []; $filters = (array) $this->config->get('plugins.simplesearch.filters'); $operator = $this->config->get('plugins.simplesearch.filter_combinator', 'and'); // see if the filter uses the new 'items-type' syntax $new_approach = false; foreach ($filters as $filter) { $filter_saved = $filter; if (is_array($filter)) { $filter = key($filter); } if (Utils::startsWith($filter, '@')) { if ($filter == '@self') { $new_approach = true; } if ($filter == '@taxonomy') { $taxonomies = $filter_saved[$filter]; } } } if ($new_approach) { $params = $page->header()->content; $params['query'] = $this->config->get('plugins.simplesearch.query'); $this->collection = $page->collection($params, false); } else { $this->collection = new Collection(); $this->collection->append($taxonomy_map->findTaxonomy($filters, $operator)->toArray()); } $extras = []; /** @var Page $cpage */ foreach ($this->collection as $cpage) { foreach ($this->query as $query) { $query = trim($query); $taxonomy_match = false; if (!empty($taxonomies)) { $page_taxonomies = $cpage->taxonomy(); foreach ((array) $taxonomies as $taxonomy) { if (array_key_exists($taxonomy, $page_taxonomies)) { $taxonomy_values = implode('|', $page_taxonomies[$taxonomy]); if (stripos($taxonomy_values, $query) !== false) { $taxonomy_match = true; break; } } } } if ($taxonomy_match === false && stripos($cpage->content(), $query) === false && stripos($cpage->title(), $query) === false) { $this->collection->remove($cpage); continue; } if ($cpage->modular()) { $this->collection->remove($cpage); $parent = $cpage->parent(); $extras[$parent->path()] = ['slug' => $parent->slug()]; } } } if (!empty($extras)) { $this->collection->append($extras); } // use a configured sorting order if not already done if (!$new_approach) { $this->collection = $this->collection->order($this->config->get('plugins.simplesearch.order.by'), $this->config->get('plugins.simplesearch.order.dir')); } // if page doesn't have settings set, create a page if (!isset($page->header()->simplesearch)) { // create the search page $page = new Page(); $page->init(new \SplFileInfo(__DIR__ . '/pages/simplesearch.md')); // override the template is set in the config $template_override = $this->config->get('plugins.simplesearch.template'); if ($template_override) { $page->template($template_override); } // fix RuntimeException: Cannot override frozen service "page" issue unset($this->grav['page']); $this->grav['page'] = $page; } }
/** * Handle the email password recovery procedure. * * @return bool True if the action was performed. */ protected function taskForgot() { $param_sep = $this->grav['config']->get('system.param_sep', ':'); $data = $this->post; $username = isset($data['username']) ? $data['username'] : ''; $user = !empty($username) ? User::load($username) : null; /** @var Language $l */ $language = $this->grav['language']; $messages = $this->grav['messages']; if (!isset($this->grav['Email'])) { $messages->add($language->translate('PLUGIN_ADMIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); $this->setRedirect('/'); return true; } if (!$user || !$user->exists()) { $messages->add($language->translate(['PLUGIN_ADMIN.FORGOT_USERNAME_DOES_NOT_EXIST', $username]), 'error'); $this->setRedirect('/forgot'); return true; } if (empty($user->email)) { $messages->add($language->translate(['PLUGIN_ADMIN.FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL', $username]), 'error'); $this->setRedirect('/forgot'); return true; } $token = md5(uniqid(mt_rand(), true)); $expire = time() + 604800; // next week $user->reset = $token . '::' . $expire; $user->save(); $author = $this->grav['config']->get('site.author.name', ''); $fullname = $user->fullname ?: $username; $reset_link = $this->grav['base_url_absolute'] . $this->grav['config']->get('plugins.login.route_reset') . '/task:login.reset/token' . $param_sep . $token . '/user' . $param_sep . $username . '/nonce' . $param_sep . Utils::getNonce('reset-form'); $sitename = $this->grav['config']->get('site.title', 'Website'); $from = $this->grav['config']->get('plugins.email.from'); if (empty($from)) { $messages->add($language->translate('PLUGIN_ADMIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error'); $this->setRedirect('/forgot'); return true; } $to = $user->email; $subject = $language->translate(['PLUGIN_ADMIN.FORGOT_EMAIL_SUBJECT', $sitename]); $content = $language->translate(['PLUGIN_ADMIN.FORGOT_EMAIL_BODY', $fullname, $reset_link, $author, $sitename]); $sent = LoginUtils::sendEmail($subject, $content, $to); if ($sent < 1) { $messages->add($language->translate('PLUGIN_ADMIN.FORGOT_FAILED_TO_EMAIL'), 'error'); } else { $messages->add($language->translate(['PLUGIN_ADMIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL', $to]), 'info'); } $this->setRedirect('/'); return true; }
/** * Finds relative CSS urls() and rewrites the URL with an absolute one * * @param $file the css source file * @param $relative_path relative path to the css file * * @return mixed */ protected function cssRewrite($file, $relative_path) { // Strip any sourcemap comments $file = preg_replace(self::CSS_SOURCEMAP_REGEX, '', $file); // Find any css url() elements, grab the URLs and calculate an absolute path // Then replace the old url with the new one $file = preg_replace_callback(self::CSS_URL_REGEX, function ($matches) use($relative_path) { $old_url = $matches[1]; // ensure this is not a data url if (strpos($old_url, 'data:') === 0) { return $matches[0]; } $new_url = $this->base_url . ltrim(Utils::normalizePath($relative_path . '/' . $old_url), '/'); return str_replace($old_url, $new_url, $matches[0]); }, $file); return $file; }
/** * Used to add a nonce to a form. Call {{ nonce_field('action') }} specifying a string representing the action. * * For maximum protection, ensure that the string representing the action is as specific as possible. * * @todo evaluate if adding referrer or not * * @param string action the action * @param string nonceParamName a custom nonce param name * * @return string the nonce input field */ public function nonceFieldFunc($action, $nonceParamName = 'nonce') { $string = '<input type="hidden" id="' . $nonceParamName . '" name="' . $nonceParamName . '" value="' . Utils::getNonce($action) . '" />'; return $string; }
/** * Gets and sets the date for this Page object. This is typically passed in via the page headers * * @param string $var string representation of a date * @return int unix timestamp representation of the date */ public function date($var = null) { if ($var !== null) { $this->date = Utils::date2timestamp($var); } if (!$this->date) { $this->date = $this->modified; } return $this->date; }
/** * Recursive function to load & build page relationships. * * @param string $directory * @param Page|null $parent * @return Page * @throws \RuntimeException * @internal */ protected function recurse($directory, Page &$parent = null) { $directory = rtrim($directory, DS); $iterator = new \DirectoryIterator($directory); $page = new Page(); /** @var Config $config */ $config = $this->grav['config']; $page->path($directory); if ($parent) { $page->parent($parent); } $page->orderDir($config->get('system.pages.order.dir')); $page->orderBy($config->get('system.pages.order.by')); // Add into instances if (!isset($this->instances[$page->path()])) { $this->instances[$page->path()] = $page; if ($parent && $page->path()) { $this->children[$parent->path()][$page->path()] = array('slug' => $page->slug()); } } else { throw new \RuntimeException('Fatal error when creating page instances.'); } // set current modified of page $last_modified = $page->modified(); // flat for content availability $content_exists = false; /** @var \DirectoryIterator $file */ foreach ($iterator as $file) { if ($file->isDot()) { continue; } $name = $file->getFilename(); if ($file->isFile()) { // Update the last modified if it's newer than already found if ($file->getBasename() !== '.DS_Store' && ($modified = $file->getMTime()) > $last_modified) { $last_modified = $modified; } if (preg_match('/^[^.].*' . CONTENT_EXT . '$/', $name)) { $page->init($file); $content_exists = true; if ($config->get('system.pages.events.page')) { $this->grav->fireEvent('onPageProcessed', new Event(['page' => $page])); } } } elseif ($file->isDir()) { if (!$page->path()) { $page->path($file->getPath()); } $path = $directory . DS . $name; $child = $this->recurse($path, $page); if (Utils::startsWith($name, '_')) { $child->routable(false); } $this->children[$page->path()][$child->path()] = array('slug' => $child->slug()); if ($config->get('system.pages.events.page')) { $this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page])); } } } // Set routability to false if no page found if (!$content_exists) { $page->routable(false); } // Override the modified and ID so that it takes the latest change into account $page->modified($last_modified); $page->id($last_modified . md5($page->filePath())); // Sort based on Defaults or Page Overridden sort order $this->children[$page->path()] = $this->sort($page); return $page; }
/** * Process an image excerpt * * @param $excerpt * @param $page * @return mixed */ public static function processImageExcerpt($excerpt, $page) { $url = $excerpt['element']['attributes']['src']; $url_parts = parse_url(htmlspecialchars_decode(urldecode($url))); if (isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) { $stream_path = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path']; $url_parts['path'] = $stream_path; unset($url_parts['host']); unset($url_parts['scheme']); } $this_host = isset($url_parts['host']) && $url_parts['host'] == Grav::instance()['uri']->host(); // if there is no host set but there is a path, the file is local if ((!isset($url_parts['host']) || $this_host) && isset($url_parts['path'])) { $path_parts = pathinfo($url_parts['path']); $media = null; // get the local path to page media if possible if ($path_parts['dirname'] == $page->url(false, false, false)) { // get the media objects for this page $media = $page->media(); } else { // see if this is an external page to this one $base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/'); $page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/'); $ext_page = Grav::instance()['pages']->dispatch($page_route, true); if ($ext_page) { $media = $ext_page->media(); } else { Grav::instance()->fireEvent('onMediaLocate', new Event(['route' => $page_route, 'media' => &$media])); } } // if there is a media file that matches the path referenced.. if ($media && isset($media->all()[$path_parts['basename']])) { // get the medium object /** @var Medium $medium */ $medium = $media->all()[$path_parts['basename']]; // Process operations $medium = static::processMediaActions($medium, $url_parts); $alt = isset($excerpt['element']['attributes']['alt']) ? $excerpt['element']['attributes']['alt'] : ''; $title = isset($excerpt['element']['attributes']['title']) ? $excerpt['element']['attributes']['title'] : ''; $class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : ''; $id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : ''; $excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true); } else { // not a current page media file, see if it needs converting to relative $excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts); } } return $excerpt; }
/** * @param $package * * @return bool|string */ private function getSymlinkSource($package) { $matches = $this->getGitRegexMatches($package); foreach ($this->local_config as $path) { if (Utils::endsWith($matches[2], '.git')) { $repo_dir = preg_replace('/\\.git$/', '', $matches[2]); } else { $repo_dir = $matches[2]; } $from = rtrim($path, '/') . '/' . $repo_dir; if (file_exists($from)) { return $from; } } return false; }
/** * Handle form processing instructions. * * @param Event $event */ public function onFormProcessed(Event $event) { $form = $event['form']; $action = $event['action']; $params = $event['params']; $this->process($form); switch ($action) { case 'captcha': if (isset($params['recaptcha_secret'])) { $recaptchaSecret = $params['recaptcha_secret']; } else { if (isset($params['recatpcha_secret'])) { // Included for backwards compatibility with typo (issue #51) $recaptchaSecret = $params['recatpcha_secret']; } else { $recaptchaSecret = $this->config->get('plugins.form.recaptcha.secret_key'); } } // Validate the captcha $query = http_build_query(['secret' => $recaptchaSecret, 'response' => $form->value('g-recaptcha-response', true)]); $url = 'https://www.google.com/recaptcha/api/siteverify?' . $query; $response = json_decode(file_get_contents($url), true); if (!isset($response['success']) || $response['success'] !== true) { $this->grav->fireEvent('onFormValidationError', new Event(['form' => $form, 'message' => $this->grav['language']->translate('PLUGIN_FORM.ERROR_VALIDATING_CAPTCHA')])); $event->stopPropagation(); return; } break; case 'ip': $label = isset($params['label']) ? $params['label'] : 'User IP'; $blueprint = $form->value()->blueprints(); $blueprint->set('form/fields/ip', ['name' => 'ip', 'label' => $label]); $form->setFields($blueprint->fields()); $form->setData('ip', Uri::ip()); break; case 'message': $translated_string = $this->grav['language']->translate($params); $vars = array('form' => $form); /** @var Twig $twig */ $twig = $this->grav['twig']; $processed_string = $twig->processString($translated_string, $vars); $form->message = $processed_string; break; case 'redirect': $this->grav['session']->setFlashObject('form', $form); $this->grav->redirect((string) $params); break; case 'reset': if (Utils::isPositive($params)) { $form->reset(); } break; case 'display': $route = (string) $params; if (!$route || $route[0] != '/') { /** @var Uri $uri */ $uri = $this->grav['uri']; $route = rtrim($uri->route(), '/') . '/' . ($route ?: ''); } /** @var Twig $twig */ $twig = $this->grav['twig']; $twig->twig_vars['form'] = $form; /** @var Pages $pages */ $pages = $this->grav['pages']; $page = $pages->dispatch($route, true); if (!$page) { throw new \RuntimeException('Display page not found. Please check the page exists.', 400); } unset($this->grav['page']); $this->grav['page'] = $page; break; case 'save': $prefix = !empty($params['fileprefix']) ? $params['fileprefix'] : ''; $format = !empty($params['dateformat']) ? $params['dateformat'] : 'Ymd-His-u'; $ext = !empty($params['extension']) ? '.' . trim($params['extension'], '.') : '.txt'; $filename = !empty($params['filename']) ? $params['filename'] : ''; $operation = !empty($params['operation']) ? $params['operation'] : 'create'; if (!$filename) { $filename = $prefix . $this->udate($format) . $ext; } /** @var Twig $twig */ $twig = $this->grav['twig']; $vars = ['form' => $form]; // Process with Twig $filename = $twig->processString($filename, $vars); $locator = $this->grav['locator']; $path = $locator->findResource('user://data', true); $dir = $path . DS . $form->name(); $fullFileName = $dir . DS . $filename; $file = File::instance($fullFileName); if ($operation == 'create') { $body = $twig->processString(!empty($params['body']) ? $params['body'] : '{% include "forms/data.txt.twig" %}', $vars); $file->save($body); } elseif ($operation == 'add') { if (!empty($params['body'])) { // use body similar to 'create' action and append to file as a log $body = $twig->processString($params['body'], $vars); // create folder if it doesn't exist if (!file_exists($dir)) { mkdir($dir); } // append data to existing file file_put_contents($fullFileName, $body, FILE_APPEND | LOCK_EX); } else { // serialize YAML out to file for easier parsing as data sets $vars = $vars['form']->value()->toArray(); foreach ($form->fields as $field) { if (isset($field['process']) && isset($field['process']['ignore']) && $field['process']['ignore']) { unset($vars[$field['name']]); } } if (file_exists($fullFileName)) { $data = Yaml::parse($file->content()); if (count($data) > 0) { array_unshift($data, $vars); } else { $data[] = $vars; } } else { $data[] = $vars; } $file->save(Yaml::dump($data)); } } break; } }
/** * Twig process that renders the site layout. This is the main twig process that renders the overall * page and handles all the layout for the site display. * * @param string $format Output format (defaults to HTML). * @return string the rendered output * @throws \RuntimeException */ public function processSite($format = null) { // set the page now its been processed $this->grav->fireEvent('onTwigSiteVariables'); $pages = $this->grav['pages']; $page = $this->grav['page']; $content = $page->content(); $config = $this->grav['config']; $twig_vars = $this->twig_vars; $twig_vars['pages'] = $pages->root(); $twig_vars['page'] = $page; $twig_vars['header'] = $page->header(); $twig_vars['content'] = $content; $ext = '.' . ($format ? $format : 'html') . TWIG_EXT; // determine if params are set, if so disable twig cache $params = $this->grav['uri']->params(null, true); if (!empty($params)) { $this->twig->setCache(false); } // Get Twig template layout $template = $this->template($page->template() . $ext); try { $output = $this->twig->render($template, $twig_vars); } catch (\Twig_Error_Loader $e) { // If loader error, and not .html.twig, try it as fallback if (Utils::contains($e->getMessage(), $template)) { $inflector = new Inflector(); $error_msg = 'The template file for this page: "' . $template . '" is not provided by the theme: "' . $inflector->titleize($config->get('system.pages.theme')) . '"'; } else { $error_msg = $e->getMessage(); } // Try html version of this template if initial template was NOT html if ($ext != '.html' . TWIG_EXT) { try { $output = $this->twig->render($page->template() . '.html' . TWIG_EXT, $twig_vars); } catch (\Twig_Error_Loader $e) { throw new \RuntimeException($error_msg, 400, $e); } } else { throw new \RuntimeException($error_msg, 400, $e); } } return $output; }
/** * Returns the items between a set of date ranges of either the page date field (default) or * an arbitrary datetime page field where end date is optional * Dates can be passed in as text that strtotime() can process * http://php.net/manual/en/function.strtotime.php * * @param $startDate * @param bool $endDate * @param $field * * @return $this * @throws \Exception */ public function dateRange($startDate, $endDate = false, $field = false) { $start = Utils::date2timestamp($startDate); $end = $endDate ? Utils::date2timestamp($endDate) : strtotime("now +1000 years"); $date_range = []; foreach ($this->items as $path => $slug) { $page = $this->pages->get($path); $date = $field ? strtotime($page->value($field)) : $page->date(); if ($date > $start && $date < $end) { $date_range[$path] = $slug; } } $this->items = $date_range; return $this; }
/** * Get the summary. * * @param int $size Max summary size. * @return string */ public function summary($size = null) { /** @var Config $config */ $config = self::getGrav()['config']->get('site.summary'); if (isset($this->header->summary)) { $config = array_merge($config, $this->header->summary); } // Return summary based on settings in site config file if (!$config['enabled']) { return $this->content(); } // Set up variables to process summary from page or from custom summary if ($this->summary === null) { $content = $this->content(); $summary_size = $this->summary_size; } else { $content = $this->summary; $summary_size = mb_strlen($this->summary); } // Return calculated summary based on summary divider's position $format = $config['format']; // Return entire page content on wrong/ unknown format if (!in_array($format, array('short', 'long'))) { return $content; } elseif ($format === 'short' && isset($summary_size)) { return mb_substr($content, 0, $summary_size); } // Get summary size from site config's file if (is_null($size)) { $size = $config['size']; } // If the size is zero, return the entire page content if ($size === 0) { return $content; // Return calculated summary based on defaults } elseif (!is_numeric($size) || $size < 0) { $size = 300; } return Utils::truncateHTML($content, $size); }
/** * This attempts to find media, other files, and download them * @param $page * @param $path */ protected function fallbackUrl($page, $path) { /** @var Uri $uri */ $uri = $this['uri']; /** @var Config $config */ $config = $this['config']; $uri_extension = $uri->extension(); $fallback_types = $config->get('system.media.allowed_fallback_types', null); $supported_types = $config->get('media'); // Check whitelist first, then ensure extension is a valid media type if (!empty($fallback_types) && !in_array($uri_extension, $fallback_types)) { return; } elseif (!array_key_exists($uri_extension, $supported_types)) { return; } $path_parts = pathinfo($path); $page = $this['pages']->dispatch($path_parts['dirname'], true); if ($page) { $media = $page->media()->all(); $parsed_url = parse_url(urldecode($uri->basename())); $media_file = $parsed_url['path']; // if this is a media object, try actions first if (isset($media[$media_file])) { $medium = $media[$media_file]; foreach ($uri->query(null, true) as $action => $params) { if (in_array($action, ImageMedium::$magic_actions)) { call_user_func_array(array(&$medium, $action), explode(',', $params)); } } Utils::download($medium->path(), false); } // unsupported media type, try to download it... if ($uri_extension) { $extension = $uri_extension; } else { if (isset($path_parts['extension'])) { $extension = $path_parts['extension']; } else { $extension = null; } } if ($extension) { $download = true; if (in_array(ltrim($extension, '.'), $config->get('system.media.unsupported_inline_types', []))) { $download = false; } Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download); } } }
/** * Generate a random string * * @param int $count * * @return string */ public function randomStringFunc($count = 5) { return Utils::generateRandomString($count); }