This commit is contained in:
Loïc Guibert
2022-09-30 20:02:02 +01:00
commit 66dafc36c3
2561 changed files with 454489 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
<?php
namespace Grav\Plugin\Form;
use GdImage;
use Grav\Common\Grav;
class BasicCaptcha
{
protected $session = null;
protected $key = 'basic_captcha_code';
public function __construct()
{
$this->session = Grav::instance()['session'];
}
public function getCaptchaCode($length = null): string
{
$config = Grav::instance()['config']->get('plugins.form.basic_captcha');
$type = $config['type'] ?? 'characters';
if ($type == 'math') {
$min = $config['math']['min'] ?? 1;
$max = $config['math']['max'] ?? 12;
$operators = $config['math']['operators'] ?? ['+','-','*'];
$first_num = random_int($min, $max);
$second_num = random_int($min, $max);
$operator = $operators[array_rand($operators)];
// calculator
if ($operator === '-') {
if ($first_num < $second_num) {
$result = "$second_num-$first_num";
$captcha_code = $second_num-$first_num;
} else {
$result = "$first_num-$second_num";
$captcha_code = $first_num - $second_num;
}
} elseif ($operator === '*') {
$result = "{$first_num}x{$second_num}";
$captcha_code = $first_num - $second_num;
} elseif ($operator === '/') {
$result = "$first_num/ second_num";
$captcha_code = $first_num / $second_num;
} elseif ($operator === '+') {
$result = "$first_num+$second_num";
$captcha_code = $first_num + $second_num;
}
} else {
if ($length === null) {
$length = $config['chars']['length'] ?? 6;
}
$random_alpha = md5(random_bytes(64));
$captcha_code = substr($random_alpha, 0, $length);
$result = $captcha_code;
}
$this->setSession($this->key, $captcha_code);
return $result;
}
public function setSession($key, $value): void
{
$this->session->$key = $value;
}
public function getSession($key = null): ?string
{
if ($key === null) {
$key = $this->key;
}
return $this->session->$key ?? null;
}
public function createCaptchaImage($captcha_code)
{
$config = Grav::instance()['config']->get('plugins.form.basic_captcha');
$font = $config['chars']['font'] ?? 'zxx-xed.ttf';
$target_layer = imagecreatetruecolor($config['chars']['box_width'], $config['chars']['box_height']);
$bg = $this->hexToRgb($config['chars']['bg'] ?? '#ffffff');
$text = $this->hexToRgb($config['chars']['text'] ?? '#000000');
$captcha_background = imagecolorallocate($target_layer, $bg[0], $bg[1], $bg[2]);
$captcha_text_color = imagecolorallocate($target_layer, $text[0], $text[1], $text[2]);
$font_path = __DIR__ . '/../fonts/' . $font;
imagefill($target_layer, 0, 0, $captcha_background);
imagefttext($target_layer, $config['chars']['size'], 0, $config['chars']['start_x'], $config['chars']['start_y'], $captcha_text_color, $font_path, $captcha_code);
return $target_layer;
}
public function renderCaptchaImage($imageData): void
{
header("Content-type: image/jpeg");
imagejpeg($imageData);
}
public function validateCaptcha($formData): bool
{
$isValid = false;
$capchaSessionData = $this->getSession();
if ($capchaSessionData == $formData) {
$isValid = true;
}
return $isValid;
}
private function hexToRgb($hex): array
{
return sscanf($hex, "#%02x%02x%02x");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
<?php declare(strict_types=1);
namespace Grav\Plugin\Form;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Page;
use Grav\Framework\Form\Interfaces\FormFactoryInterface;
use Grav\Framework\Form\Interfaces\FormInterface;
class FormFactory implements FormFactoryInterface
{
/**
* Create form using the header of the page.
*
* @param Page $page
* @param string $name
* @param array $form
* @return Form|null
* @deprecated 1.6 Use FormFactory::createFormByPage() instead.
*/
public function createPageForm(Page $page, string $name, array $form): ?FormInterface
{
return new Form($page, $name, $form);
}
/**
* Create form using the header of the page.
*
* @param PageInterface $page
* @param string $name
* @param array $form
* @return Form|null
*/
public function createFormForPage(PageInterface $page, string $name, array $form): ?FormInterface
{
return new Form($page, $name, $form);
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace Grav\Plugin\Form;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Page;
use Grav\Framework\Form\Interfaces\FormFactoryInterface;
use Grav\Framework\Form\Interfaces\FormInterface;
class Forms
{
/** @var array|FormFactoryInterface[] */
private $types;
/** @var FormInterface|null */
private $form;
/**
* Forms constructor.
*/
public function __construct()
{
$this->registerType('form', new FormFactory());
}
/**
* @param string $type
* @param FormFactoryInterface $factory
*/
public function registerType(string $type, FormFactoryInterface $factory): void
{
$this->types[$type] = $factory;
}
/**
* @param string $type
*/
public function unregisterType($type): void
{
unset($this->types[$type]);
}
/**
* @param string $type
* @return bool
*/
public function hasType(string $type): bool
{
return isset($this->types[$type]);
}
/**
* @return array
*/
public function getTypes(): array
{
return array_keys($this->types);
}
/**
* @param PageInterface $page
* @param string|null $name
* @param array|null $form
* @return FormInterface|null
*/
public function createPageForm(PageInterface $page, string $name = null, array $form = null): ?FormInterface
{
if (null === $form) {
[$name, $form] = $this->getPageParameters($page, $name);
}
if (null === $form) {
return null;
}
$type = $form['type'] ?? 'form';
$factory = $this->types[$type] ?? null;
if ($factory) {
if (is_callable([$factory, 'createFormForPage'])) {
return $factory->createFormForPage($page, $name, $form);
}
if ($page instanceof Page) {
// @phpstan-ignore-next-line
return $factory->createPageForm($page, $name, $form);
}
}
return null;
}
/**
* @return FormInterface|null
*/
public function getActiveForm(): ?FormInterface
{
return $this->form;
}
/**
* @param FormInterface $form
* @return void
*/
public function setActiveForm(FormInterface $form): void
{
$this->form = $form;
}
/**
* @param PageInterface $page
* @param string|null $name
* @return array
*/
protected function getPageParameters(PageInterface $page, ?string $name): array
{
$forms = $page->getForms();
if ($name) {
// If form with given name was found, use that.
$form = $forms[$name] ?? null;
} else {
// Otherwise pick up the first form.
$form = reset($forms) ?: null;
$name = (string)key($forms);
}
return [$name, $form];
}
}

View File

@@ -0,0 +1,163 @@
<?php declare(strict_types=1);
namespace Grav\Plugin\Form;
use Grav\Framework\Form\Interfaces\FormInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use function is_string;
/**
* Class GravExtension
* @package Grav\Common\Twig\Extension
*/
class TwigExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('value_and_label', [$this, 'valueAndLabel'])
];
}
/**
* Return a list of all functions.
*
* @return array
*/
public function getFunctions(): array
{
return [
new TwigFunction('prepare_form_fields', [$this, 'prepareFormFields'], ['needs_context' => true]),
new TwigFunction('prepare_form_field', [$this, 'prepareFormField'], ['needs_context' => true]),
new TwigFunction('include_form_field', [$this, 'includeFormField']),
];
}
public function valueAndLabel($value): array
{
if (!is_array($value)) {
return [];
}
$list = [];
foreach ($value as $key => $label) {
$list[] = ['value' => $key, 'label' => $label];
}
return $list;
}
/**
* Filters form fields for the current parent.
*
* @param array $context
* @param array $fields Form fields
* @param string|null $parent Parent field name if available
* @return array
*/
public function prepareFormFields(array $context, $fields, $parent = null): array
{
$list = [];
if (is_iterable($fields)) {
foreach ($fields as $name => $field) {
$field = $this->prepareFormField($context, $field, $name, $parent);
if ($field) {
$list[$field['name']] = $field;
}
}
}
return $list;
}
/**
* Filters field name by changing dot notation into array notation.
*
* @param array $context
* @param array $field Form field
* @param string|int|null $name Field name (defaults to field.name)
* @param string|null $parent Parent field name if available
* @param array|null $options List of options to override
* @return array|null
*/
public function prepareFormField(array $context, $field, $name = null, $parent = null, array $options = []): ?array
{
// Make sure that the field is a valid form field type and is not being ignored.
if (empty($field['type']) || ($field['validate']['ignore'] ?? false)) {
return null;
}
// If field has already been prepared, we do not need to do anything.
if (!empty($field['prepared'])) {
return $field;
}
// Check if we have just a list of fields (no name given).
$fieldName = (string)($field['name'] ?? $name);
if (!is_string($name) || $name === '') {
// Look at the field.name and if not set, fall back to the key.
$name = $fieldName;
}
// Make sure that the field has a name.
if ($name === '') {
return null;
}
// Prefix name with the parent name if needed.
if (str_starts_with($name, '.')) {
$plainName = (string)substr($name, 1);
$field['plain_name'] = $plainName;
$name = $parent ? $parent . $name : $plainName;
} elseif (isset($options['key'])) {
$name = str_replace('*', $options['key'], $name);
}
unset($options['key']);
// Set fields as readonly if form is in readonly mode.
/** @var FormInterface $form */
$form = $context['form'] ?? null;
if ($form && method_exists($form, 'isEnabled') && !$form->isEnabled()) {
$options['disabled'] = true;
}
// Loop through options
foreach ($options as $key => $option) {
$field[$key] = $option;
}
// Always set field name.
$field['name'] = $name;
$field['prepared'] = true;
return $field;
}
/**
* @param string $type
* @param string|string[]|null $layouts
* @param string|null $default
* @return string[]
*/
public function includeFormField(string $type, $layouts = null, string $default = null): array
{
$list = [];
foreach ((array)$layouts as $layout) {
$list[] = "forms/fields/{$type}/{$layout}-{$type}.html.twig";
}
$list[] = "forms/fields/{$type}/{$type}.html.twig";
if ($default) {
foreach ((array)$layouts as $layout) {
$list[] = "forms/fields/{$default}/{$layout}-{$default}.html.twig";
}
$list[] = "forms/fields/{$default}/{$default}.html.twig";
}
return $list;
}
}