public function testGetExtension() { $file = 'picture-of-kittens.jpg'; $this->assertEquals('jpg', Library::getExtension($file)); $empty = '/path/to/noext'; $this->assertEquals('', Library::getExtension($empty)); }
public function patchTranslationPath() { # workaround for Bolt 2.2 - fix in master (3.0), see #3553 and #3800 // $app->before(function() use ($app) { // $path = $app['resources']->getPath('root/app/resources/translations'); // $app['translator']->addResource('yml', $path.'/contenttypes.de_DE.yml', 'de_DE', 'contenttypes'); // }); if ("Bolt\\Configuration\\Composer" != get_class($this->app['resources'])) { return; } // $versionParser = new \Composer\Package\Version\VersionParser(); // $version = $versionParser->parseConstraints($app['bolt_version']); // print_r($version); // Directory to look for translation file(s) $transDir = $this->app['resources']->getPath('root/app/resources/translations/' . $this->app['locale']); if (is_dir($transDir)) { $iterator = new \DirectoryIterator($transDir); /** * @var \SplFileInfo $fileInfo */ foreach ($iterator as $fileInfo) { $ext = Lib::getExtension((string) $fileInfo); if (!$fileInfo->isFile() || !in_array($ext, array('yml', 'xlf'))) { continue; } list($domain) = explode('.', $fileInfo->getFilename()); $this->app['translator']->addResource($ext, $transDir . '/' . $fileInfo->getFilename(), $this->app['locale'], $domain); } } }
/** * Adds all resources that belong to a locale. * * @param Application $app * @param string $locale */ public static function addResources(Application $app, $locale) { // Directories to look for translation file(s) $transDirs = array_unique([$app['resources']->getPath("app/resources/translations/{$locale}"), $app['resources']->getPath("root/app/resources/translations/{$locale}")]); $needsSecondPass = true; foreach ($transDirs as $transDir) { if (!is_dir($transDir) || !is_readable($transDir)) { continue; } $iterator = new \DirectoryIterator($transDir); /** * @var \SplFileInfo $fileInfo */ foreach ($iterator as $fileInfo) { $ext = Lib::getExtension((string) $fileInfo); if (!$fileInfo->isFile() || !in_array($ext, ['yml', 'xlf'], true)) { continue; } list($domain) = explode('.', $fileInfo->getFilename()); $app['translator']->addResource($ext, $fileInfo->getRealPath(), $locale, $domain); $needsSecondPass = false; } } if ($needsSecondPass && strlen($locale) === 5) { static::addResources($app, substr($locale, 0, 2)); } }
/** * Checks if a given file is acceptable for upload. * * @param string $originalFilename * * @return bool */ public function allowedUpload($originalFilename) { // no UNIX-hidden files if ($originalFilename[0] === '.') { return false; } // only whitelisted extensions $extension = strtolower(Lib::getExtension($originalFilename)); $allowedExtensions = $this->getAllowedUploadExtensions(); return in_array($extension, $allowedExtensions); }
/** * Checks if a given file is acceptable for upload. * * @param string $originalFilename * * @throws IOException * * @return bool */ public function allowedUpload($originalFilename) { // Check if file_uploads ini directive is true if (ini_get('file_uploads') != 1) { throw new IOException('File uploads are not allowed, check the file_uploads ini directive.'); } // no UNIX-hidden files if ($originalFilename[0] === '.') { return false; } // only whitelisted extensions $extension = strtolower(Lib::getExtension($originalFilename)); $allowedExtensions = $this->getAllowedUploadExtensions(); return in_array($extension, $allowedExtensions); }
/** * Adds all resources that belong to a locale. * * @param Application $app * @param string $locale */ public static function addResources(Application $app, $locale) { // Directory to look for translation file(s) $transDir = $app['resources']->getPath('app/resources/translations/' . $locale); if (is_dir($transDir)) { $iterator = new \DirectoryIterator($transDir); /** * @var \SplFileInfo $fileInfo */ foreach ($iterator as $fileInfo) { $ext = Lib::getExtension((string) $fileInfo); if (!$fileInfo->isFile() || !in_array($ext, ['yml', 'xlf'])) { continue; } list($domain) = explode('.', $fileInfo->getFilename()); $app['translator']->addResource($ext, $fileInfo->getRealPath(), $locale, $domain); } } elseif (strlen($locale) == 5) { static::addResources($app, substr($locale, 0, 2)); } }
/** * File editor. * * @param Request $request The Symfony Request * @param string $namespace The filesystem namespace * @param string $file The file path * * @return \Bolt\Response\BoltResponse|\Symfony\Component\HttpFoundation\RedirectResponse */ public function edit(Request $request, $namespace, $file) { if ($namespace === 'app' && dirname($file) === 'config') { // Special case: If requesting one of the major config files, like contenttypes.yml, set the path to the // correct dir, which might be 'app/config', but it might be something else. $namespace = 'config'; } /** @var FilesystemInterface $filesystem */ $filesystem = $this->filesystem()->getFilesystem($namespace); if (!$filesystem->authorized($file)) { $error = Trans::__('general.phrase.access-denied-permissions-edit-file', ['%s' => $file]); $this->abort(Response::HTTP_FORBIDDEN, $error); } try { /** @var File $file */ $file = $filesystem->get($file); $type = Lib::getExtension($file->getPath()); $data = ['contents' => $file->read()]; } catch (FileNotFoundException $e) { $error = Trans::__('general.phrase.file-not-exist', ['%s' => $file->getPath()]); $this->abort(Response::HTTP_NOT_FOUND, $error); } catch (IOException $e) { $error = Trans::__('general.phrase.file-not-readable', ['%s' => $file->getPath()]); $this->abort(Response::HTTP_NOT_FOUND, $error); } /** @var Form $form */ $form = $this->createFormBuilder(FormType::class, $data)->add('contents', TextareaType::class)->getForm(); // Handle the POST and check if it's valid. if ($request->isMethod('POST')) { return $this->handleEdit($request, $form, $file, $type); } // For 'related' files we might need to keep track of the current dirname on top of the namespace. if (dirname($file->getPath()) !== '') { $additionalpath = dirname($file->getPath()) . '/'; } else { $additionalpath = ''; } $context = ['form' => $form->createView(), 'filetype' => $type, 'file' => $file->getPath(), 'basename' => basename($file->getPath()), 'pathsegments' => $this->getPathSegments(dirname($file->getPath())), 'additionalpath' => $additionalpath, 'namespace' => $namespace, 'write_allowed' => true, 'filegroup' => $this->getFileGroup($filesystem, $file), 'datechanged' => date_format(new \DateTime('@' . $file->getTimestamp()), 'c')]; return $this->render('@bolt/editfile/editfile.twig', $context); }
/** * File editor. * * @param Request $request The Symfony Request * @param string $namespace The filesystem namespace * @param string $file The file path * * @return \Bolt\Response\BoltResponse|\Symfony\Component\HttpFoundation\RedirectResponse */ public function edit(Request $request, $namespace, $file) { if ($namespace === 'app' && dirname($file) === 'config') { // Special case: If requesting one of the major config files, like contenttypes.yml, set the path to the // correct dir, which might be 'app/config', but it might be something else. $namespace = 'config'; } /** @var FilesystemInterface $filesystem */ $filesystem = $this->filesystem()->getFilesystem($namespace); if (!$filesystem->authorized($file)) { $error = Trans::__("You don't have correct permissions to edit the file '%s'.", ['%s' => $file]); $this->abort(Response::HTTP_FORBIDDEN, $error); } /** @var File $file */ $file = $filesystem->get($file); $type = Lib::getExtension($file->getPath()); $contents = null; if (!$file->exists() || !($contents = $file->read())) { $error = Trans::__("The file '%s' doesn't exist, or is not readable.", ['%s' => $file->getPath()]); $this->abort(Response::HTTP_NOT_FOUND, $error); } $writeallowed = $this->isWriteable($file); $data = ['contents' => $contents]; /** @var Form $form */ $form = $this->createFormBuilder('form', $data)->add('contents', 'textarea')->getForm(); // Handle the POST and check if it's valid. if ($request->isMethod('POST')) { return $this->handleEdit($request, $form, $file, $type); } // For 'related' files we might need to keep track of the current dirname on top of the namespace. if (dirname($file->getPath()) !== '') { $additionalpath = dirname($file->getPath()) . '/'; } else { $additionalpath = ''; } $context = ['form' => $form->createView(), 'filetype' => $type, 'file' => $file->getPath(), 'basename' => basename($file->getPath()), 'pathsegments' => $this->getPathSegments(dirname($file->getPath())), 'additionalpath' => $additionalpath, 'namespace' => $namespace, 'write_allowed' => $writeallowed, 'filegroup' => $this->getFileGroup($filesystem, $file), 'datechanged' => date_format(new \DateTime('@' . $file->getTimestamp()), 'c')]; return $this->render('@bolt/editfile/editfile.twig', $context); }
/** * Return a list with the current stacked items. Add some relevant info to each item, * and also check if the item is present and readable. * * @param integer $count * @param string $typefilter * * @return array */ public function listitems($count = 100, $typefilter = '') { $this->initialize(); // Make sure typefilter is an array, if passed something like "image, document" if (!empty($typefilter)) { $typefilter = array_map('trim', explode(',', $typefilter)); } // Our basepaths for all files that can be on the stack: 'files' and 'theme'. $filespath = $this->app['resources']->getPath('filespath'); $themepath = $this->app['resources']->getPath('themebasepath'); $items = $this->items; $list = []; foreach ($items as $item) { $extension = strtolower(Lib::getExtension($item)); if (in_array($extension, $this->imageTypes)) { $type = 'image'; } elseif (in_array($extension, $this->documentTypes)) { $type = 'document'; } else { $type = 'other'; } // Skip this one, if it doesn't match the type. if (!empty($typefilter) && !in_array($type, $typefilter)) { continue; } // Figure out the full path, based on the two possible locations. $fullpath = ''; if (is_readable(str_replace('files/files/', 'files/', $filespath . '/' . $item))) { $fullpath = str_replace('files/files/', 'files/', $filespath . '/' . $item); } elseif (is_readable($themepath . '/' . $item)) { $fullpath = $themepath . '/' . $item; } // No dice! skip this one. if (empty($fullpath)) { continue; } $thisitem = ['basename' => basename($item), 'extension' => $extension, 'filepath' => str_replace('files/', '', $item), 'type' => $type, 'writable' => is_writable($fullpath), 'readable' => is_readable($fullpath), 'filesize' => Lib::formatFilesize(filesize($fullpath)), 'modified' => date('Y/m/d H:i:s', filemtime($fullpath)), 'permissions' => util::full_permissions($fullpath)]; $thisitem['info'] = sprintf('%s: <code>%s</code><br>%s: %s<br>%s: %s<br>%s: <code>%s</code>', Trans::__('Path'), $thisitem['filepath'], Trans::__('Filesize'), $thisitem['filesize'], Trans::__('Modified'), $thisitem['modified'], Trans::__('Permissions'), $thisitem['permissions']); if ($type == 'image') { $size = getimagesize($fullpath); $thisitem['imagesize'] = sprintf('%s × %s', $size[0], $size[1]); $thisitem['info'] .= sprintf('<br>%s: %s × %s px', Trans::__('Size'), $size[0], $size[1]); } //add it to our list. $list[] = $thisitem; } $list = array_slice($list, 0, $count); return $list; }
/** * File editor. * * @param string $namespace The filesystem namespace * @param string $file The file path * @param Application $app The application/container * @param Request $request The Symfony Request * * @return \Twig_Markup|\Symfony\Component\HttpFoundation\RedirectResponse */ public function fileEdit($namespace, $file, Application $app, Request $request) { if ($namespace == 'app' && dirname($file) == 'config') { // Special case: If requesting one of the major config files, like contenttypes.yml, set the path to the // correct dir, which might be 'app/config', but it might be something else. $namespace = 'config'; } /** @var \League\Flysystem\FilesystemInterface $filesystem */ $filesystem = $app['filesystem']->getFilesystem($namespace); if (!$filesystem->authorized($file)) { $error = Trans::__("You don't have correct permissions to edit the file '%s'.", array('%s' => $file)); $app->abort(Response::HTTP_FORBIDDEN, $error); } /** @var \League\Flysystem\File $file */ $file = $filesystem->get($file); $datechanged = date_format(new \DateTime('@' . $file->getTimestamp()), 'c'); $type = Lib::getExtension($file->getPath()); // Get the pathsegments, so we can show the path. $path = dirname($file->getPath()); $pathsegments = array(); $cumulative = ''; if (!empty($path)) { foreach (explode('/', $path) as $segment) { $cumulative .= $segment . '/'; $pathsegments[$cumulative] = $segment; } } $contents = null; if (!$file->exists() || !($contents = $file->read())) { $error = Trans::__("The file '%s' doesn't exist, or is not readable.", array('%s' => $file->getPath())); $app->abort(Response::HTTP_NOT_FOUND, $error); } if (!$file->update($contents)) { $app['session']->getFlashBag()->add('info', Trans::__("The file '%s' is not writable. You will have to use your own editor to make modifications to this file.", array('%s' => $file->getPath()))); $writeallowed = false; } else { $writeallowed = true; } // Gather the 'similar' files, if present.. i.e., if we're editing config.yml, we also want to check for // config.yml.dist and config_local.yml $basename = str_replace('.yml', '', str_replace('_local', '', $file->getPath())); $filegroup = array(); if ($filesystem->has($basename . '.yml')) { $filegroup[] = basename($basename . '.yml'); } if ($filesystem->has($basename . '_local.yml')) { $filegroup[] = basename($basename . '_local.yml'); } $data = array('contents' => $contents); /** @var Form $form */ $form = $app['form.factory']->createBuilder('form', $data)->add('contents', 'textarea')->getForm(); // Check if the form was POST-ed, and valid. If so, store the user. if ($request->isMethod('POST')) { $form->submit($app['request']->get($form->getName())); if ($form->isValid()) { $data = $form->getData(); $contents = Input::cleanPostedData($data['contents']) . "\n"; $result = array('ok' => true, 'msg' => 'Unhandled state.'); // Before trying to save a yaml file, check if it's valid. if ($type === 'yml') { $yamlparser = new Yaml\Parser(); try { $yamlparser->parse($contents); } catch (ParseException $e) { $result['ok'] = false; $result['msg'] = Trans::__("File '%s' could not be saved:", array('%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.", array('%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.", array('%s' => $file->getPath())); } } } else { $result = array('ok' => false, 'msg' => Trans::__("File '%s' could not be saved, because the form wasn't valid.", array('%s' => $file->getPath()))); } return new JsonResponse($result); } // For 'related' files we might need to keep track of the current dirname on top of the namespace. if (dirname($file->getPath()) != '') { $additionalpath = dirname($file->getPath()) . '/'; } else { $additionalpath = ''; } $context = array('form' => $form->createView(), 'filetype' => $type, 'file' => $file->getPath(), 'basename' => basename($file->getPath()), 'pathsegments' => $pathsegments, 'additionalpath' => $additionalpath, 'namespace' => $namespace, 'write_allowed' => $writeallowed, 'filegroup' => $filegroup, 'datechanged' => $datechanged); return $app['render']->render('editfile/editfile.twig', array('context' => $context)); }