PageRenderTime 39ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/user/plugins/form/classes/form.php

https://gitlab.com/asun89/socianovation-web
PHP | 285 lines | 185 code | 45 blank | 55 comment | 33 complexity | 8ca2686be114193800d6029f5354de0a MD5 | raw file
  1. <?php
  2. namespace Grav\Plugin;
  3. use Grav\Common\Filesystem\Folder;
  4. use Grav\Common\Iterator;
  5. use Grav\Common\GravTrait;
  6. use Grav\Common\Page\Page;
  7. use Grav\Common\Data\Data;
  8. use Grav\Common\Data\Blueprint;
  9. use Grav\Common\Utils;
  10. use RocketTheme\Toolbox\Event\Event;
  11. class Form extends Iterator
  12. {
  13. use GravTrait;
  14. /**
  15. * @var string
  16. */
  17. public $message;
  18. /**
  19. * @var array
  20. */
  21. protected $data = array();
  22. /**
  23. * @var array
  24. */
  25. protected $rules = array();
  26. /**
  27. * @var array
  28. */
  29. protected $items = array();
  30. /**
  31. * @var array
  32. */
  33. protected $values = array();
  34. /**
  35. * @var Page $page
  36. */
  37. protected $page;
  38. /**
  39. * Create form for the given page.
  40. *
  41. * @param Page $page
  42. */
  43. public function __construct(Page $page)
  44. {
  45. $this->page = $page;
  46. $header = $page->header();
  47. $this->rules = isset($header->rules) ? $header->rules : array();
  48. $this->data = isset($header->data) ? $header->data : array();
  49. $this->items = $header->form;
  50. // Set form name if not set.
  51. if (empty($this->items['name'])) {
  52. $this->items['name'] = $page->slug();
  53. }
  54. $this->reset();
  55. // Fire event
  56. self::getGrav()->fireEvent('onFormInitialized', new Event(['form' => $this]));
  57. }
  58. /**
  59. * Reset values.
  60. */
  61. public function reset()
  62. {
  63. $name = $this->items['name'];
  64. // Fix naming for fields (presently only for toplevel fields)
  65. foreach ($this->items['fields'] as $key => $field) {
  66. if (is_numeric($key) && isset($field['name'])) {
  67. unset($this->items['fields'][$key]);
  68. $key = $field['name'];
  69. $this->items['fields'][$key] = $field;
  70. }
  71. }
  72. $blueprint = new Blueprint($name, ['form' => $this->items, 'rules' => $this->rules]);
  73. $this->values = new Data($this->data, $blueprint);
  74. }
  75. /**
  76. * Return page object for the form.
  77. *
  78. * @return Page
  79. */
  80. public function page()
  81. {
  82. return $this->page;
  83. }
  84. /**
  85. * Get value of given variable (or all values).
  86. *
  87. * @param string $name
  88. *
  89. * @return mixed
  90. */
  91. public function value($name = null)
  92. {
  93. if (!$name) {
  94. return $this->values;
  95. }
  96. return $this->values->get($name);
  97. }
  98. /**
  99. * Set value of given variable.
  100. *
  101. * @param string $name
  102. *
  103. * @return mixed
  104. */
  105. public function setValue($name = null, $value = '')
  106. {
  107. if (!$name) {
  108. return;
  109. }
  110. $this->values->set($name, $value);
  111. }
  112. /**
  113. * Handle form processing on POST action.
  114. */
  115. public function post()
  116. {
  117. $files = [];
  118. if (isset($_POST)) {
  119. $values = (array)$_POST;
  120. $files = (array)$_FILES;
  121. if (method_exists('Grav\Common\Utils', 'getNonce')) {
  122. if (!isset($values['form-nonce']) || !Utils::verifyNonce($values['form-nonce'], 'form')) {
  123. $event = new Event(['form' => $this, 'message' => self::getGrav()['language']->translate('PLUGIN_FORM.NONCE_NOT_VALIDATED')]);
  124. self::getGrav()->fireEvent('onFormValidationError', $event);
  125. return;
  126. }
  127. }
  128. unset($values['form-nonce']);
  129. foreach ($this->items['fields'] as $field) {
  130. $name = $field['name'];
  131. if ($field['type'] == 'checkbox') {
  132. $values[$name] = isset($values[$name]) ? true : false;
  133. }
  134. }
  135. // Add post values to form dataset
  136. $this->values->merge($values);
  137. $this->values->merge($files);
  138. }
  139. // Validate and filter data
  140. try {
  141. $this->values->validate();
  142. $this->values->filter();
  143. foreach ($files as $key => $file) {
  144. $cleanFiles = $this->cleanFilesData($key, $file);
  145. if ($cleanFiles) {
  146. $this->values->set($key, $cleanFiles);
  147. }
  148. }
  149. self::getGrav()->fireEvent('onFormValidationProcessed', new Event(['form' => $this]));
  150. } catch (\RuntimeException $e) {
  151. $event = new Event(['form' => $this, 'message' => $e->getMessage()]);
  152. self::getGrav()->fireEvent('onFormValidationError', $event);
  153. if ($event->isPropagationStopped()) {
  154. return;
  155. }
  156. }
  157. $process = isset($this->items['process']) ? $this->items['process'] : array();
  158. if (is_array($process)) {
  159. $event = null;
  160. foreach ($process as $action => $data) {
  161. if (is_numeric($action)) {
  162. $action = \key($data);
  163. $data = $data[$action];
  164. }
  165. $previousEvent = $event;
  166. $event = new Event(['form' => $this, 'action' => $action, 'params' => $data]);
  167. if ($previousEvent) {
  168. if (!$previousEvent->isPropagationStopped()) {
  169. self::getGrav()->fireEvent('onFormProcessed', $event);
  170. }
  171. } else {
  172. self::getGrav()->fireEvent('onFormProcessed', $event);
  173. }
  174. }
  175. } else {
  176. // Default action.
  177. }
  178. }
  179. private function cleanFilesData($key, $file)
  180. {
  181. $config = self::getGrav()['config'];
  182. $default = $config->get('plugins.form.files');
  183. $settings = isset($this->items['fields'][$key]) ? $this->items['fields'][$key] : [];
  184. /** @var Page $page */
  185. $page = null;
  186. $blueprint = array_replace($default, $settings);
  187. $cleanFiles[$key] = [];
  188. if (!isset($blueprint)) {
  189. return false;
  190. }
  191. $cleanFiles = [$key => []];
  192. foreach ((array)$file['error'] as $index => $error) {
  193. if ($error == UPLOAD_ERR_OK) {
  194. $tmp_name = $file['tmp_name'][$index];
  195. $name = $file['name'][$index];
  196. $type = $file['type'][$index];
  197. $destination = Folder::getRelativePath(rtrim($blueprint['destination'], '/'));
  198. if (!$this->match_in_array($type, $blueprint['accept'])) {
  199. throw new \RuntimeException('File "' . $name . '" is not an accepted MIME type.');
  200. }
  201. if (Utils::startsWith($destination, '@page:')) {
  202. $parts = explode(':', $destination);
  203. $route = $parts[1];
  204. $page = self::getGrav()['page']->find($route);
  205. if (!$page) {
  206. throw new \RuntimeException('Unable to upload file to destination. Page route not found.');
  207. }
  208. $destination = $page->relativePagePath();
  209. } else if ($destination == '@self') {
  210. $page = self::getGrav()['page'];
  211. $destination = $page->relativePagePath();
  212. } else {
  213. Folder::mkdir($destination);
  214. }
  215. if (move_uploaded_file($tmp_name, "$destination/$name")) {
  216. $path = $page ? self::getGrav()['uri']->convertUrl($page, $page->route() . '/' . $name) : $destination . '/' . $name;
  217. $cleanFiles[$key][$path] = [
  218. 'name' => $file['name'][$index],
  219. 'type' => $file['type'][$index],
  220. 'size' => $file['size'][$index],
  221. 'file' => $destination . '/' . $name,
  222. 'route' => $page ? $path : null
  223. ];
  224. } else {
  225. throw new \RuntimeException("Unable to upload file(s) to $destination/$name");
  226. }
  227. }
  228. }
  229. return $cleanFiles[$key];
  230. }
  231. private function match_in_array($needle, $haystack)
  232. {
  233. foreach ((array)$haystack as $item) {
  234. if (true == preg_match("#^" . strtr(preg_quote($item, '#'), array('\*' => '.*', '\?' => '.')) . "$#i", $needle)) {
  235. return true;
  236. }
  237. }
  238. return false;
  239. }
  240. }