public function testCleanPostedData() { // Test flat value $val = "test\r\n\v\f"; $this->assertEquals('test ', Input::cleanPostedData($val, false, true)); // Test tabs convert to spaces $val = "test\t"; $this->assertEquals('test ', Input::cleanPostedData($val, false, true)); // Test on array $vals = ['first' => "test\r\n", 'second' => "test\t"]; $this->assertEquals(['first' => 'test ', 'second' => 'test '], Input::cleanPostedData($vals, false, true)); }
public function testCleanPostedData() { // Test flat value $val = "test\r\n\v\f"; $this->assertEquals('test ', Input::cleanPostedData($val, false, true)); // Test tabs convert to spaces $val = "test\t"; $this->assertEquals('test ', Input::cleanPostedData($val, false, true)); // Test on array $vals = array('first' => "test\r\n", 'second' => "test\t"); $this->assertEquals(array('first' => 'test ', 'second' => 'test '), Input::cleanPostedData($vals, false, true)); // Test Slashed $vals = array('first' => "\\\"test\\\"", 'second' => "a \\\"test\\\" val"); $this->assertEquals(array('first' => '"test"', 'second' => 'a "test" val'), Input::cleanPostedData($vals, true, true)); }
/** * Handle a file edit POST. * * @param Request $request * @param Form $form * @param File $file * @param string $type * * @return JsonResponse */ private function handleEdit(Request $request, Form $form, File $file, $type) { $form->submit($request->get($form->getName())); if ($form->isValid()) { $data = $form->getData(); $contents = Input::cleanPostedData($data['contents']) . "\n"; $result = ['ok' => true, 'msg' => 'Unhandled state.']; // Before trying to save a yaml file, check if it's valid. if ($type === 'yml') { $yamlparser = new Parser(); try { $yamlparser->parse($contents); } catch (ParseException $e) { $result['ok'] = false; $result['msg'] = Trans::__('page.file-management.message.save-failed-colon', ['%s' => $file->getPath()]) . $e->getMessage(); } } if ($result['ok']) { // Remove ^M (or \r) characters from the file. $contents = str_ireplace("\r", '', $contents); try { $file->update($contents); $result['msg'] = Trans::__('page.file-management.message.save-success', ['%s' => $file->getPath()]); $result['datechanged'] = $file->getCarbon()->toIso8601String(); } catch (ExceptionInterface $e) { $result['msg'] = Trans::__('page.file-management.message.save-failed-unknown', ['%s' => $file->getPath()]); } } } else { $result = ['ok' => false, 'msg' => Trans::__('page.file-management.message.save-failed-invalid-form', ['%s' => $file->getPath()])]; } return $this->json($result); }
/** * Attempt to save the POST data for a translation file edit. * * @param string $contents * @param array $tr * * @return boolean|\Symfony\Component\HttpFoundation\RedirectResponse */ private function saveTranslationFile($contents, array &$tr) { $contents = Input::cleanPostedData($contents) . "\n"; // Before trying to save a yaml file, check if it's valid. try { Yaml::parse($contents); } catch (ParseException $e) { $msg = Trans::__("File '%s' could not be saved:", ['%s' => $tr['shortPath']]); $this->flashes()->error($msg . ' ' . $e->getMessage()); return false; } // Clear any warning for file not found, we are creating it here // we'll set an error if someone still submits the form and write is not allowed $this->flashes()->clear(); try { $fs = new Filesystem(); $fs->dumpFile($tr['path'], $contents); } catch (IOException $e) { $msg = Trans::__("The file '%s' is not writable. You will have to use your own editor to make modifications to this file.", ['%s' => $tr['shortPath']]); $this->flashes()->error($msg); $tr['writeallowed'] = false; return false; } $msg = Trans::__("File '%s' has been saved.", ['%s' => $tr['shortPath']]); $this->flashes()->info($msg); return $this->redirectToRoute('translation', ['domain' => $tr['domain'], 'tr_locale' => $tr['locale']]); }
/** * The search result page controller. * * @param Request $request The Symfony Request * @param array $contenttypes The content type slug(s) you want to search for * * @return BoltResponse */ public function search(Request $request, array $contenttypes = null) { $q = ''; $context = __FUNCTION__; if ($request->query->has('q')) { $q = $request->query->get('q'); } elseif ($request->query->has($context)) { $q = $request->query->get($context); } $q = Input::cleanPostedData($q, false); $page = $this->app['pager']->getCurrentPage($context); // Theme value takes precedence over default config @see https://github.com/bolt/bolt/issues/3951 $pageSize = $this->getOption('theme/search_results_records', false); if ($pageSize === false && !($pageSize = $this->getOption('general/search_results_records', false))) { $pageSize = $this->getOption('theme/listing_records', false) ?: $this->getOption('general/listing_records', 10); } $offset = ($page - 1) * $pageSize; $limit = $pageSize; // set-up filters from URL $filters = []; foreach ($request->query->all() as $key => $value) { if (strpos($key, '_') > 0) { list($contenttypeslug, $field) = explode('_', $key, 2); if (isset($filters[$contenttypeslug])) { $filters[$contenttypeslug][$field] = $value; } else { $contenttype = $this->getContentType($contenttypeslug); if (is_array($contenttype)) { $filters[$contenttypeslug] = [$field => $value]; } } } } if (count($filters) == 0) { $filters = null; } $result = $this->storage()->searchContent($q, $contenttypes, $filters, $limit, $offset); /** @var \Bolt\Pager\PagerManager $manager */ $manager = $this->app['pager']; $manager->createPager($context)->setCount($result['no_of_results'])->setTotalpages(ceil($result['no_of_results'] / $pageSize))->setCurrent($page)->setShowingFrom($offset + 1)->setShowingTo($offset + count($result['results'])); $manager->setLink($this->generateUrl('search', ['q' => $q]) . '&page_search='); $globals = ['records' => $result['results'], $context => $result['query']['use_q'], 'searchresult' => $result]; $template = $this->templateChooser()->search(); return $this->render($template, [], $globals); }
/** * The search result page controller. * * @param Request $request The Symfony Request * @param array $contenttypes The content type slug(s) you want to search for * * @return BoltResponse */ public function search(Request $request, array $contenttypes = null) { $q = ''; $context = __FUNCTION__; if ($request->query->has('q')) { $q = $request->query->get('q'); } elseif ($request->query->has($context)) { $q = $request->query->get($context); } $q = Input::cleanPostedData($q, false); $param = Pager::makeParameterId($context); $page = $request->query->get($param, $request->query->get('page', 1)); $pageSize = $this->getOption('general/search_results_records') ?: ($this->getOption('general/listing_records') ?: 10); $offset = ($page - 1) * $pageSize; $limit = $pageSize; // set-up filters from URL $filters = []; foreach ($request->query->all() as $key => $value) { if (strpos($key, '_') > 0) { list($contenttypeslug, $field) = explode('_', $key, 2); if (isset($filters[$contenttypeslug])) { $filters[$contenttypeslug][$field] = $value; } else { $contenttype = $this->getContentType($contenttypeslug); if (is_array($contenttype)) { $filters[$contenttypeslug] = [$field => $value]; } } } } if (count($filters) == 0) { $filters = null; } $result = $this->app['storage']->searchContent($q, $contenttypes, $filters, $limit, $offset); $pager = ['for' => $context, 'count' => $result['no_of_results'], 'totalpages' => ceil($result['no_of_results'] / $pageSize), 'current' => $page, 'showing_from' => $offset + 1, 'showing_to' => $offset + count($result['results']), 'link' => $this->generateUrl('search', ['q' => $q]) . '&page_search=']; $this->app['storage']->setPager($context, $pager); $globals = ['records' => $result['results'], $context => $result['query']['use_q'], 'searchresult' => $result]; $template = $this->templateChooser()->search(); return $this->render($template, [], $globals); }
/** * Set a Contenttype record values from a HTTP POST. * * @param array $values * @param string $contenttype * * @throws \Exception * * @return void */ public function setFromPost($values, $contenttype) { $values = Input::cleanPostedData($values); if (!$this->id) { // this is a new record: current user becomes the owner. $user = $this->app['users']->getCurrentUser(); $this['ownerid'] = $user['id']; } // If the owner is set explicitly, check if the current user is allowed // to do this. if (isset($values['ownerid'])) { if ($this['ownerid'] != $values['ownerid']) { if (!$this->app['users']->isAllowed("contenttype:{$contenttype['slug']}:change-ownership:{$this->id}")) { throw new \Exception('Changing ownership is not allowed.'); } $this['ownerid'] = intval($values['ownerid']); } } // Make sure we have a proper status. if (!in_array($values['status'], ['published', 'timed', 'held', 'draft'])) { if ($this['status']) { $values['status'] = $this['status']; } else { $values['status'] = "draft"; } } // Make sure we only get the current taxonomies, not those that were fetched from the DB. $this->taxonomy = []; if (!empty($values['taxonomy'])) { foreach ($values['taxonomy'] as $taxonomytype => $value) { if (isset($values['taxonomy-order'][$taxonomytype])) { foreach ($value as $k => $v) { $value[$k] = $v . '#' . $values['taxonomy-order'][$taxonomytype]; } } $this->taxonomy[$taxonomytype] = $value; } unset($values['taxonomy']); unset($values['taxonomy-order']); } // Get the relations from the POST-ed values. if (!empty($values['relation']) && is_array($values['relation'])) { foreach ($values['relation'] as $key => $relationValues) { $this->clearRelation($key); foreach ($relationValues as $value) { $this->setRelation($key, $value); } } unset($values['relation']); } else { $this->relation = []; } $this->setValues($values); }
/** * Set a Contenttype record values from a HTTP POST. * * @param array $values * @param string $contenttype * * @throws \Exception * * @return void */ public function setFromPost($values, $contenttype) { $values = Input::cleanPostedData($values); if (!$this->id) { // this is a new record: current user becomes the owner. $user = $this->app['users']->getCurrentUser(); $this['ownerid'] = $user['id']; } // If the owner is set explicitly, check if the current user is allowed // to do this. if (isset($values['ownerid'])) { if ($this['ownerid'] != $values['ownerid']) { if (!$this->app['users']->isAllowed("contenttype:{$contenttype['slug']}:change-ownership:{$this->id}")) { throw new \Exception("Changing ownership is not allowed."); } $this['ownerid'] = intval($values['ownerid']); } } // Make sure we have a proper status. if (!in_array($values['status'], ['published', 'timed', 'held', 'draft'])) { if ($this['status']) { $values['status'] = $this['status']; } else { $values['status'] = "draft"; } } // Make sure we only get the current taxonomies, not those that were fetched from the DB. $this->taxonomy = []; if (!empty($values['taxonomy'])) { foreach ($values['taxonomy'] as $taxonomytype => $value) { if (!is_array($value)) { $value = explode(",", $value); } if (isset($values['taxonomy-order'][$taxonomytype])) { foreach ($value as $k => $v) { $value[$k] = $v . "#" . $values['taxonomy-order'][$taxonomytype]; } } $this->taxonomy[$taxonomytype] = $value; } unset($values['taxonomy']); unset($values['taxonomy-order']); } // Get the relations from the POST-ed values. // @todo use $this->setRelation() for this if (!empty($values['relation'])) { $this->relation = $values['relation']; unset($values['relation']); } else { $this->relation = []; } // @todo check for allowed file types. // Handle file-uploads. if (!empty($_FILES)) { foreach ($_FILES as $key => $file) { if (empty($file['name'][0])) { continue; // Skip 'empty' uploads. } $paths = $this->app['resources']->getPaths(); $filename = sprintf('%sfiles/%s/%s', $paths['rootpath'], date('Y-m'), Str::makeSafe($file['name'][0], false, '[]{}()')); $basename = sprintf('/%s/%s', date('Y-m'), Str::makeSafe($file['name'][0], false, "[]{}()")); if ($file['error'][0] != UPLOAD_ERR_OK) { $message = 'Error occured during upload: ' . $file['error'][0] . " - {$filename}"; $this->app['logger.system']->error($message, ['event' => 'upload']); continue; } if (substr($key, 0, 11) != 'fileupload-') { $message = "Skipped an upload that wasn't for content: {$filename}"; $this->app['logger.system']->error($message, ['event' => 'upload']); continue; } $fieldname = substr($key, 11); $fileSystem = new Filesystem(); // Make sure the folder exists. $fileSystem->mkdir(dirname($filename)); // Check if we don't have doubles. if (is_file($filename)) { while (is_file($filename)) { $filename = $this->upcountName($filename); $basename = $this->upcountName($basename); } } if (is_writable(dirname($filename))) { // Yes, we can create the file! move_uploaded_file($file['tmp_name'][0], $filename); $values[$fieldname] = $basename; $this->app['logger.system']->info("Upload: uploaded file '{$basename}'.", ['event' => 'upload']); } else { $this->app['logger.system']->error("Upload: couldn't write upload '{$basename}'.", ['event' => 'upload']); } } } $this->setValues($values); }
/** * Set a Contenttype record values from a HTTP POST. * * @param Content $content * @param array $formValues * @param array $contentType * * @throws AccessControlException */ private function setPostedValues(Content $content, $formValues, $contentType) { // Ensure all fields have valid values $formValues = $this->setSuccessfulControlValues($formValues, $contentType['fields']); $formValues = Input::cleanPostedData($formValues); unset($formValues['contenttype']); if ($id = $content->getId()) { // Owner is set explicitly, is current user is allowed to do this? if (isset($formValues['ownerid']) && (int) $formValues['ownerid'] !== $content->getOwnerid()) { if (!$this->app['permissions']->isAllowed("contenttype:{$contentType['slug']}:change-ownership:{$id}")) { throw new AccessControlException('Changing ownership is not allowed.'); } $content->setOwnerid($formValues['ownerid']); } } else { $user = $this->app['users']->getCurrentUser(); $content->setOwnerid($user['id']); } // Make sure we have a proper status. if (!in_array($formValues['status'], ['published', 'timed', 'held', 'draft'])) { if ($status = $content->getStatus()) { $formValues['status'] = $status; } else { $formValues['status'] = 'draft'; } } // Set the object values appropriately foreach ($formValues as $name => $value) { if ($name === 'relation') { $this->setPostedRelations($content, $formValues); } elseif ($name === 'taxonomy') { $this->setPostedTaxonomies($content, $formValues); } else { $content->set($name, empty($value) ? null : $value); } } }
/** * Handle a file edit POST. * * @param Request $request * @param Form $form * @param File $file * @param string $type * * @return JsonResponse */ private function handleEdit(Request $request, Form $form, File $file, $type) { $form->submit($request->get($form->getName())); if ($form->isValid()) { $data = $form->getData(); $contents = Input::cleanPostedData($data['contents']) . "\n"; $result = ['ok' => true, 'msg' => 'Unhandled state.']; // Before trying to save a yaml file, check if it's valid. if ($type === 'yml') { $yamlparser = new Parser(); try { $yamlparser->parse($contents); } catch (ParseException $e) { $result['ok'] = false; $result['msg'] = Trans::__("File '%s' could not be saved:", ['%s' => $file->getPath()]) . $e->getMessage(); } } if ($result['ok']) { // Remove ^M (or \r) characters from the file. $contents = str_ireplace("\r", '', $contents); if ($file->update($contents)) { $result['msg'] = Trans::__("File '%s' has been saved.", ['%s' => $file->getPath()]); $result['datechanged'] = date_format(new \DateTime('@' . $file->getTimestamp()), 'c'); } else { $result['msg'] = Trans::__("File '%s' could not be saved, for some reason.", ['%s' => $file->getPath()]); } } } else { $result = ['ok' => false, 'msg' => Trans::__("File '%s' could not be saved, because the form wasn't valid.", ['%s' => $file->getPath()])]; } return $this->json($result); }
/** * Attempt to save the POST data for a translation file edit. * * @param string $contents * @param array $tr * * @return boolean|\Symfony\Component\HttpFoundation\RedirectResponse */ private function saveTranslationFile($contents, array &$tr) { $contents = Input::cleanPostedData($contents) . "\n"; // Before trying to save a yaml file, check if it's valid. try { Yaml::parse($contents); } catch (ParseException $e) { $msg = Trans::__('page.file-management.message.save-failed-colon', ['%s' => $tr['shortPath']]); $this->flashes()->error($msg . ' ' . $e->getMessage()); return false; } // Clear any warning for file not found, we are creating it here // we'll set an error if someone still submits the form and write is not allowed $this->flashes()->clear(); try { $fs = new Filesystem(); $fs->dumpFile($tr['path'], $contents); } catch (IOException $e) { $msg = Trans::__('general.phrase.file-not-writable', ['%s' => $tr['shortPath']]); $this->flashes()->error($msg); $tr['writeallowed'] = false; return false; } $msg = Trans::__('page.file-management.message.save-success', ['%s' => $tr['shortPath']]); $this->flashes()->info($msg); return $this->redirectToRoute('translation', ['domain' => $tr['domain'], 'tr_locale' => $tr['locale']]); }
/** * Modify a record's value if permitted. * * @param Content $entity * @param string $field * @param mixed $value */ protected function modifyRecordValue(Content $entity, $field, $value) { $recordId = $entity->getId(); $contentTypeName = (string) $entity->getContenttype(); $canModify = $this->users->isAllowed("contenttype:{$contentTypeName}:edit:{$recordId}"); if (!$canModify) { $this->loggerFlash->error(Trans::__('general.access-denied.content-not-modified', ['%title%' => $entity->getTitle()])); return; } $entity->{$field} = Input::cleanPostedData($value); $entity->_modified = true; }
/** * The search result page controller. * * @param Request $request The Symfony Request * @param \Silex\Application $app The application/container * @param array $contenttypes The content type slug(s) you want to search for * * @return \Twig_Markup */ public function search(Request $request, Silex\Application $app, array $contenttypes = null) { $q = ''; $context = __FUNCTION__; if ($request->query->has('q')) { $q = $request->get('q'); } elseif ($request->query->has($context)) { $q = $request->get($context); } $q = Input::cleanPostedData($q, false); $param = Pager::makeParameterId($context); /* @var $query \Symfony\Component\HttpFoundation\ParameterBag */ $query = $request->query; $page = $query ? $query->get($param, $query->get('page', 1)) : 1; $config = $app['config']; $pageSize = $config->get('general/search_results_records') ?: ($config->get('general/listing_records') ?: 10); $offset = ($page - 1) * $pageSize; $limit = $pageSize; // set-up filters from URL $filters = array(); foreach ($request->query->all() as $key => $value) { if (strpos($key, '_') > 0) { list($contenttypeslug, $field) = explode('_', $key, 2); if (isset($filters[$contenttypeslug])) { $filters[$contenttypeslug][$field] = $value; } else { $contenttype = $app['storage']->getContentType($contenttypeslug); if (is_array($contenttype)) { $filters[$contenttypeslug] = array($field => $value); } } } } if (count($filters) == 0) { $filters = null; } $result = $app['storage']->searchContent($q, $contenttypes, $filters, $limit, $offset); $pager = array('for' => $context, 'count' => $result['no_of_results'], 'totalpages' => ceil($result['no_of_results'] / $pageSize), 'current' => $page, 'showing_from' => $offset + 1, 'showing_to' => $offset + count($result['results']), 'link' => $app['url_generator']->generate('search', array('q' => $q)) . '&page_search='); $app['storage']->setPager($context, $pager); $app['twig']->addGlobal('records', $result['results']); $app['twig']->addGlobal($context, $result['query']['use_q']); $app['twig']->addGlobal('searchresult', $result); $template = $app['templatechooser']->search(); return $this->render($app, $template, 'search'); }
/** * Prepare/edit/save a translation. * * @param string $domain The domain * @param string $tr_locale The translation locale * @param Application $app The application/container * @param Request $request The Symfony Request * * @return \Twig_Markup|\Symfony\Component\HttpFoundation\RedirectResponse */ public function translation($domain, $tr_locale, Application $app, Request $request) { $translation = new TranslationFile($app, $domain, $tr_locale); list($path, $shortPath) = $translation->path(); $app['logger.system']->info('Editing translation: ' . $shortPath, array('event' => 'translation')); $data = array('contents' => $translation->content()); $writeallowed = $translation->isWriteAllowed(); $form = $app['form.factory']->createBuilder('form', $data)->add('contents', 'textarea', array('constraints' => array(new Assert\NotBlank(), new Assert\Length(array('min' => 10)))))->getForm(); // Check if the form was POST-ed, and valid. If so, store the file. if ($request->isMethod('POST')) { $form->submit($app['request']->get($form->getName())); if ($form->isValid()) { $data = $form->getData(); $contents = Input::cleanPostedData($data['contents']) . "\n"; // Before trying to save a yaml file, check if it's valid. try { $ok = Yaml\Yaml::parse($contents); } catch (ParseException $e) { $ok = false; $msg = Trans::__("File '%s' could not be saved:", array('%s' => $shortPath)); $app['session']->getFlashBag()->add('error', $msg . $e->getMessage()); } // Before trying to save, check if it's writable. if ($ok) { // clear any warning for file not found, we are creating it here // we'll set an error if someone still submits the form and write is not allowed $app['session']->getFlashBag()->clear('warning'); if (!$writeallowed) { $msg = Trans::__("The file '%s' is not writable. You will have to use your own editor to make modifications to this file.", array('%s' => $shortPath)); $app['session']->getFlashBag()->add('error', $msg); } else { file_put_contents($path, $contents); $msg = Trans::__("File '%s' has been saved.", array('%s' => $shortPath)); $app['session']->getFlashBag()->add('info', $msg); return Lib::redirect('translation', array('domain' => $domain, 'tr_locale' => $tr_locale)); } } } } $context = array('form' => $form->createView(), 'basename' => basename($shortPath), 'filetype' => 'yml', 'write_allowed' => $writeallowed); return $app['render']->render('editlocale/editlocale.twig', array('context' => $context)); }
/** * Handle a file edit POST. * * @param FormInterface $form * @param FileInterface $file * * @return JsonResponse */ private function handleEdit(FormInterface $form, FileInterface $file) { if (!$form->isValid()) { return $this->json(['ok' => false, 'msg' => Trans::__('page.file-management.message.save-failed-invalid-form', ['%s' => $file->getPath()])]); } $data = $form->getData(); $contents = Input::cleanPostedData($data['contents']) . "\n"; // Remove ^M and \r characters from the file. $contents = str_ireplace("\r", '', $contents); // Before trying to save a yaml file, check if it's valid. if ($file->getType() === 'yaml') { $yamlparser = new Parser(); try { $yamlparser->parse($contents); } catch (ParseException $e) { return $this->json(['ok' => false, 'msg' => Trans::__('page.file-management.message.save-failed-colon', ['%s' => $file->getPath()]) . $e->getMessage()]); } } try { $file->update($contents); } catch (ExceptionInterface $e) { return $this->json(['ok' => false, 'msg' => Trans::__('page.file-management.message.save-failed-unknown', ['%s' => $file->getPath()])]); } return $this->json(['ok' => true, 'msg' => Trans::__('page.file-management.message.save-success', ['%s' => $file->getPath()]), 'datechanged' => $file->getCarbon()->toIso8601String()]); }