[], ]; $contentRoot = dirname(__DIR__) . '/content'; $method = $request->getMethod(); $path = $request->getPathInfo(); try { $config = $this->buildConfig($contentRoot . $path); // check api key $apiKey = $_GET['key'] ?? $_POST['key'] ?? null; if (empty($apiKey)) { $response->setStatusCode(Response::HTTP_BAD_REQUEST); throw new \Exception('API key missing'); } if (! in_array($apiKey, $config['api']['keys'])) { $response->setStatusCode(Response::HTTP_UNAUTHORIZED); throw new \Exception('API key does not match'); } // GET if ($method == 'GET') { if (str_ends_with($path, '/fields')) { $formPath = $contentRoot . str_replace('/fields', '', $path); $content['data'] = $this->buildFields($formPath); } else { $content['data'] = Toml::parseFile($contentRoot . $path . '.toml'); } } // POST else if ($method == 'POST') { if (str_ends_with($path, '/submit')) { $formPath = $contentRoot . str_replace('/submit', '', $path); $fields = $this->buildFields($formPath); $fields = $this->validateFields($fields); // remove surplus fields from response $fields = array_map(function ($field) { return array_intersect_key($field, array_flip([ 'is_valid', ])); }, $fields); $content['data'] = $fields; $hasInvalidFields = in_array(false, array_column($fields, 'is_valid')); if ($hasInvalidFields) { $content['error'] = 'Invalid fields'; } else { $date = new \Datetime(); $entry = [ 'fields' => $_POST, 'date' => $date->format('c'), ]; $builder = new TomlBuilder(); $builder->addValue('date', $entry['date']); $builder->addTable('fields'); foreach ($entry['fields'] as $entryKey => $entryValue) { $builder->addValue($entryKey, $entryValue); } $entryDirectory = $formPath . '/entries/' . $date->format('Y/m/d'); @mkdir($entryDirectory, 0774, true); $entryFilename = $date->format('Ymd_Hi_') . hash('adler32', serialize($entry)) . '.toml'; file_put_contents( $entryDirectory . '/' . $entryFilename, $builder->getTomlString() ); } } } } catch (\Exception $exception) { $content['error'] = $exception->getMessage(); } $response->headers->set('Content-Type', 'application/json'); $response->setContent(json_encode($content)); $response->send(); } /** * @param string $formPath */ public function buildFields($formPath) { $fields = Toml::parseFile($formPath . '/fields/_fields.toml')['field'] ?? []; foreach ($fields as $key => $field) { if (! empty($field['file'])) { $field = array_replace_recursive($field, Toml::parseFile($formPath . '/fields/' . $field['file'])); } if (empty($field['name'])) { $field['name'] = $key; } $fields[$key] = $field; } return $fields; } /** * @param array $fields */ public function validateFields($fields) { foreach ($fields as $key => &$field) { $field['is_valid'] = true; if (($field['required'] ?? false) && empty($_POST[$field['name']])) { $field['is_valid'] = false; } } return $fields; } /** * @param string $formPath */ public function buildConfig($formPath) { $config = []; $currentFolder = $formPath; while (true) { $configFile = $currentFolder . '/config/config.toml'; if (file_exists($configFile)) { $parsedConfig = Toml::parseFile($configFile); $apiKeys = array_merge($parsedConfig['api']['keys'] ?? [], $config['api']['keys'] ?? []); $config = array_replace_recursive($parsedConfig, $config); $config['api']['keys'] = $apiKeys; } if (str_ends_with($currentFolder, '/content') || $currentFolder == '/') { break; } $currentFolder = dirname($currentFolder); } return $config; } }