Bildiğimiz gibi symfony framework'un resimlerin tutulduğu ve de herkes tarafından ulaşıma açık olan klasörü www'dur, ki bunun malum durumlarda herhangi bir sakıncası yoktur. Bunun haricinde, bazen resimleri ulaşıma kapalı olan klasörlerde tutmamız gerekir ve de sadece ulaşım hakkı olan kişilere göstermemiz gerekebilir. Bu örneğimizde resimleri app/Resources/private/uploads/images klasörüne yükleyip, controller yardımıyla twig şablonunda göstereceğiz.


Mantık


Resimler app/Resources/private/uploads/images klasörüne yüklenecek. İş resimleri göstermeye geldiğinde ise, twig şablonu içinde <img src="{{ path('image_show', {'name': image_name}) }}" /> kodunu kullanarak controller yardımıyla resmi göstereceğiz. HTML kaynak kodunda resmin linki <img src="/app_dev.php/6f3f48c823a61a2919ad6092ffe0f1e0.png"> olarak görünecek ki burada resmin tam adresi gizlenmiş durumdadır.


İzinler


$ HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
$ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/Resources/private/uploads/images
$ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/Resources/private/uploads/images

parameters.yml


parameters:
image_upload_path: '%kernel.root_dir%/Resources/private/uploads/images'

routing.yml


inanzzz_application:
resource: "@InanzzzApplicationBundle/Controller/"
type: annotation
prefix: /

ImageController


Örneği kısa kesmek için tüm mantığı controller içinde tutuyorum ama bilin ki, bu iyi birşey değildir.


namespace Inanzzz\ApplicationBundle\Controller;

use Inanzzz\ApplicationBundle\Form\Model\ImageUpload as ImageUploadModel;
use Inanzzz\ApplicationBundle\Form\Type\ImageUploadType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\RouterInterface;

/**
* @Route("", service="inanzzz_application.controller.image")
*/
class ImageController
{
private $templating;
private $formFactory;
private $router;
private $imageUploadPath;

public function __construct(
EngineInterface $templating,
FormFactoryInterface $formFactory,
RouterInterface $router,
$imageUploadPath
) {
$this->templating = $templating;
$this->formFactory = $formFactory;
$this->router = $router;
$this->imageUploadPath = $imageUploadPath;
}

/**
* @Method({"GET"})
* @Route("/", name="image_index")
*
* @return Response
*/
public function indexAction()
{
return $this->templating->renderResponse(
'InanzzzApplicationBundle:Image:index.html.twig',
[
'form' => $this->createForm()->createView(),
'images' => $this->getImages(),
]
);
}

/**
* @param string $name
*
* @Method({"GET"})
* @Route("/{name}", name="image_show")
*
* @return Response
*/
public function showAction($name)
{
$response = new BinaryFileResponse($this->imageUploadPath.'/'.$name);
$response->trustXSendfileTypeHeader();
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_INLINE,
$name,
iconv('UTF-8', 'ASCII//TRANSLIT', $name)
);

return $response;
}

/**
* @param Request $request
*
* @Method({"POST"})
* @Route("/upload/image", name="image_upload_image")
*
* @return Response
*/
public function uploadImageAction(Request $request)
{
$imageUploadModel = new ImageUploadModel();

$form = $this->createForm($imageUploadModel);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {

/** @var UploadedFile $image */
$image = $imageUploadModel->image;
$name = md5(uniqid().microtime().$image->getClientOriginalName()).'.'.$image->guessExtension();

$image->move($this->imageUploadPath, $name);
}

return new RedirectResponse($this->router->generate('image_index'));
}

private function createForm(ImageUploadModel $imageUploadModel = null)
{
return $this->formFactory->create(
ImageUploadType::class,
$imageUploadModel ? $imageUploadModel : new ImageUploadModel(),
[
'method' => 'POST',
'action' => $this->router->generate('image_upload_image')
]
);
}

private function getImages()
{
$images = [];

$finder = new Finder();
$finder->files()->in($this->imageUploadPath);

/** @var SplFileInfo $file */
foreach ($finder as $file) {
$images[] = $file->getFilename();
}

return $images;
}
}

Buda controller servis tanımlaması.


services:
inanzzz_application.controller.image:
class: Inanzzz\ApplicationBundle\Controller\ImageController
arguments:
- '@templating'
- '@form.factory'
- '@router'
- '%image_upload_path%'

index.html.twig


{% block body %}
<p>Upload!</p>

<hr />
{{ form_start(form) }}
{{ form_row(form.image) }}
<button type="submit">Upload</button>
{{ form_end(form) }}

<hr />
{% for image in images %}
<img src="{{ path('image_show', {'name': image}) }}" />
{% else %}
<em>No image found.</em>
{% endfor %}
{% endblock %}

ImageUploadType


namespace Inanzzz\ApplicationBundle\Form\Type;

use Inanzzz\ApplicationBundle\Form\Model\ImageUpload as ImageUploadModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;

class ImageUploadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('image', FileType::class, ['label' => 'Select an image']);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => ImageUploadModel::class]);
}
}

ImageUpload


Kullanıcının verisini kontrol etmiyorum ama siz mutlaka kontrolünüzü yapın. Tekrar, işi kısa kesiyorum.


namespace Inanzzz\ApplicationBundle\Form\Model;

class ImageUpload
{
public $image;
}