I read a lot of article about the problem but it seems that there has to be no answer yet to this.
So my project directory is like :
+ uploads_dir
+ symfony_proj
- app
- bin
- src
- vendor
- web
I want to get the image inside the uploads_dir for me to use in my view page
I created twig extension that fetches the roor directory.. but it seems not to read if I put "root_dir"."../../uploads_dir".
Any suggestions ?
Here is the my twig extension part of it:
/**
* #var container
*/
protected $container;
public function __construct(ContainerInterface $container){
$this->container = $container;
}
public function bannerFilter($filename)
{
$file = $this->container->getParameter('kernel.root_dir').'../../uploads_dir'.$filename;
}
I would make the getting of a resource go through a function, this also enables your to do any kind of other checks (like is user logged in, etc).
Create a controller action that processes the request, and then in your twig you can just use a normal path() function.
Some sample code;
parameters.yml
parameters:
upload_destination: '%kernel.root_dir%/../../uploads_dir'
Sample function;
public function getFileAction($file_name)
{
$base_path = $this->container->getParameter('upload_destination');
$full_path = $base_path . '/' . $file_name;
$fs = new FileSystem();
if (!$fs->exists($full_path)) {
throw $this->createNotFoundException();
}
$file_name = basename($full_path);
$mime_type = $this->getMimeType($full_path);
$file = readfile($full_path);
$headers = array(
'Content-Type' => $mime_type,
'Content-Disposition' => 'inline; filename="'.$file_name.'"');
return new Response($file, 200, $headers);
}
protected function getMimeType($file)
{
if ('jpg' === substr($file, -3)) {
$best_guess = 'jpeg';
} else {
$guesser = MimeTypeGuesser::getInstance();
$best_guess = $guesser->guess($file);
}
return $best_guess;
}
In your twig;
<img src="{{ path('whatever_you_called_your_route', {'file_name': 'my_file.jpg'}) }}" />
I got passed this by using /uploads_dir/.
I hopes this helps.
Related
How do i clear the cache of my patterned url (dynamic url)?
Like, /assets/js/#jsname.js...
I don't want to wait until the cache expired, i want to it, immediately after i updated things on my database.
They said that to clear the database, you need to specify the key for it. And i don't know what should i enter for the key :(
Here's my code:
\F3::route("GET #virtualasset: /assets/img/#link/#size.#id.#type", "Control\\Imager->akses", 3600 * 24 * 7); // cache seminggu :3
HTTP responses are cached using the following key: hash(VERB URI).url.
So if you want to refresh assets/js/foo.js, you'll have to do:
$hash=$f3->hash('GET /assets/js/foo.js');
$cache->clear($hash.'.url');
But that's a bit of a hack since this key is not documented and may change in the future.
Also you need to remember that the route $ttl parameter not only triggers server cache but also client cache. Which means that you need to implement a cache buster to refresh the client cache. Something like assets/js/foo.js?v=3.
You may consider implementing cache directly in your controller class. That would give you more flexibility.
I use this route:
GET|HEAD /assets/#folder/#type/v-#version/* = controllers\Assets->send, 3600
My controller:
namespace controllers;
class Assets {
private $paths;
private $types = ['css', 'js', 'i', 'fonts', 'files', 'icons'];
private $dontminify = ['i', 'fonts', 'files', 'icons'];
public function __construct() {
$this->fw = \Base::instance();
$this->paths['app'] = '../app/views/site_tpl/assets/';
$this->paths['core'] = '../core/views/default/assets/';
}
public function send() {
if (in_array($this->fw->get('PARAMS.folder'), array_keys($this->paths))
&& in_array($this->fw->get('PARAMS.type'), $this->types))
{
$folder = $this->paths[$this->fw->get('PARAMS.folder')];
$type = $this->fw->get('PARAMS.type');
if (in_array($type, $this->dontminify)) {
$file = $folder . $type . '/' . $this->fw->pop('PARAMS');
if (\Web::instance()->send($file)) {
return true;
}
} else {
$this->fw->set('UI', $folder . $type . '/');
$file = $this->fw->pop('PARAMS');
if (file_exists($this->fw->get('UI') . $file)) {
if (!$this->fw->exists('GET.dontminify')) {
echo \Web::instance()->minify($file);
return true;
} elseif (\Web::instance()->send($this->fw->get('UI') . $file)) {
return true;
}
}
}
}
$this->fw->error(404);
}
}
So, when I want to update version of file, I write somethong like this:
<script src="/assets/app/js/v-20160205/main.js"></script>
I'm facing following problem and can't seem to figure this one out.
I wrote an API endpoint accepting a POST with binary data (header: content-type:image/jpeg).
I know i can read out the raw string with file_get_content('php://input') or Laravel's $request->getContent().
PHP also has a function createimagefromstring($string) which also seems to read the string in correctly.
What i'd like to do is create an UploadedFile from this raw data , so that I can handle it with already written functions.
Is this possible?
Thank you in advance
I think I found it... Still curious if there are improvements that can be made..
$imgRaw = imagecreatefromstring( $request->getContent() );
if ($imgRaw !== false) {
imagejpeg($imgRaw, storage_path().'/tmp/tmp.jpg',100);
imagedestroy($imgRaw);
$file = new UploadedFile( storage_path().'/tmp/tmp.jpg', 'tmp.jpg', 'image/jpeg',null,null,true);
// DO STUFF WITH THE UploadedFile
}
You can try to use base64 encoding. Symfony have some nice stuff for this.
Your code will be smthng like this:
$base64Content = $request->request->get('base64Content'); // this is your post data
$yourFile = new UploadedBase64EncodedFile(new Base64EncodedFile($base64Content)); // this is an instance of UploadedFile
Hope it helps!
As per Laravel 8
Just follow the constructor:
* #param string $path The full temporary path to the file
* #param string $originalName The original file name of the uploaded file
* #param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream
* #param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
* #param bool $test Whether the test mode is active
$file = new UploadedFile(
$pathIncludingFilename,
$fileName,
'image/jpeg',
null,
false
);
There is no need to manually create it, Symfony parses received $_FILES array for you. Http Request object has a FileBag property called $files with a get() method which returns an UploadedFile instance.
/** #var UploadedFile $file */
$file = $request->files->get('user-pictures-upload')[0];
$cmd = new UploadPictureCmd($file, $this->getUser()->getId());
Here is the example of generating images files using fzaninotto/faker in Symfony 4 Fixtures
class FileFixtures extends Fixture
{
private $faker;
private $parameterBag;
public function __construct(ParameterBagInterface $parameterBag)
{
$this->faker = Factory::create();
$this->parameterBag = $parameterBag;
}
public function load(ObjectManager $manager)
{
$tempFixturesPath = $this->parameterBag->get('kernel.project_dir') . '/tmp';
if (!file_exists($tempFixturesPath)) {
mkdir($tempFixturesPath);
}
$fileName = $this->faker->image($tempFixturesPath, 640, 480, 'cats', false, true);
$file = new UploadedFile($tempFixturesPath . '/' . $fileName, $fileName, 'image/jpeg', null, null, true);
//do something with $file
}
}
If it counts for anything, this is how I did it in Laravel 5.4. In my case, I wanted to be able to easily resize an image and be able to do something like this.
request()->file('image')->resize(250, 250)->store('path/to/storage');
This is what I did to the UploadedFile class.
Illuminate\Http\UploadedFile.php ~this file ships with the Laravel framework
public function resize($w, $h) {
$image = Intervention::make($this)->fit($w, $h)->save($this->getPathname());
$filesize = filesize($this->getPathname());
return new static(
$this->getPathname(),
$this->getClientOriginalName(),
$this->getClientMimeType(),
$filesize,
null,
false
);
}
Using Intervention, I resized the image that is stored in the /tmp/ folder when files are uploaded and then I saved it in the same place. Now all I do after that is create an instance of UploadedFile so that I can keep using Laravel's methods on request()->file('image'). Hope this helps.
I'm working on a Symfony2 project.
I created a simple TempFile class to manipulate an UploadFile. Here is my constructor :
public function __construct(UploadedFile $file, $destination, $suffix)
{
$this->file = $file;
$this->destination = $destination;
$this->fileId = sprintf('%s_%s', uniqid(), (string) $suffix);
}
And my move method
public function move()
{
$extension = $this->file->guessExtension();
if (!$extension) {
throw new \Exception(__METHOD__ . ' -> Unable to detect extension');
}
$this->tmpFileName = sprintf('%s.%s', $this->fileId, $extension);
$this->file->move($this->destination, $this->tmpFileName);
}
I try to create an UploadFile object in my test and here is what I did :
protected function setUp()
{
$this->file = tempnam(sys_get_temp_dir(), 'upload');
imagepng(imagecreatetruecolor(10, 10), $this->file);
$this->uploadedFile = new UploadedFile($this->file, "test.png");
}
public function testMoveWithAValidUploadedFile()
{
$tempFile = new TempFile($this->uploadedFile, '/tmp', 'tmp');
$tempFile->move();
// Future assertion
}
I have the following error :
Symfony\Component\HttpFoundation\File\Exception\FileException: The file "test.png" was not uploaded due to an unknown error
Any ideas ?
Thx,
Regards
From memory, Symfony2 checks if a file was uploaded as part of the request using is_uploaded_file(). This can be overridden using the test mode of the UploadedFile class. You can also define which PHP upload error code constitutes success.
copy(__DIR__ . '/Fixtures/test.pdf', '/tmp/test.pdf');
new UploadedFile(
'/tmp/test.pdf',
'original.pdf',
null,
null,
UPLOAD_ERR_OK,
true /* test */
)
I'm trying to display an image stored outside the 'public' folder in my view. These are simple profile images whose paths are stored in the DB. The path looks like
/Users/myuser/Documents/Sites/myapp/app/storage/tenants/user2/images/52d645738fb9d-128-Profile (Color) copy.jpg
Since the image is stored a DB column for each user, my first thought was to create an Accessor in the User model to return the image. I tried:
public function getProfileImage()
{
if(!empty($this->profile_image))
{
return readfile($this->profile_image);
}
return null;
}
That produced unreadable characters in the view. I also tried file_get_contents() in place of read file. Any suggestions about how this might be accomplished?
How about this (just tested it myself and it works):
The view:
<img src="/images/theImage.png">
Routes.php:
Route::get('images/{image}', function($image = null)
{
$path = storage_path().'/imageFolder/' . $image;
if (file_exists($path)) {
return Response::download($path);
}
});
Here is a slightly modified version of #Mattias answer. Assume the file is in the storage/app/avatars folder which is outside the web root.
<img src="/avatars/3">
Route::get('/avatars/{userId}', function($image = null)
{
$path = storage_path().'/app/avatars/' . $image.'.jpg';
if (file_exists($path)) {
return response()->file($path);
}
});
Probably needs and else. Also I have wrapped mine inside the middleware auth Route Group which means you have to be logged in to see (my requirements) but I could do with more control over when it is made visible, perhaps alter the middleware.
EDIT
Forgot to mention that this is for Laravel 5.3.
Here's what I came up with:
I'm trying to show the images in the view, not download. Here's what I came up with:
Note that these images are stored above the public folder, which is why we have to take extra steps to display the image in the view.
The view
{{ HTML::image($user->getProfileImage(), '', array('height' => '50px')) }}
The model
/**
* Get profile image
*
*
*
* #return string
*/
public function getProfileImage()
{
if(!empty($this->profile_image) && File::exists($this->profile_image))
{
$subdomain = subdomain();
// Get the filename from the full path
$filename = basename($this->profile_image);
return 'images/image.php?id='.$subdomain.'&imageid='.$filename;
}
return 'images/missing.png';
}
public/images/image.php
<?php
$tenantId = $_GET["id"];
$imageId = $_GET["imageid"];
$path = __DIR__.'/../../app/storage/tenants/' . $tenantId . '/images/profile/' . $imageId;
// Prepare content headers
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $path);
$length = filesize($path);
header ("content-type: $mime");
header ("content-length: $length");
// #TODO: Cache images generated from this php file
readfile($path);
exit;
?>
If somebody has a better way, please enlighten us!! I'm very interested.
I am trying to use phpThumb in my application by making a custom autoloader.
class My_Loader_Autoloader_PhpThumb implements Zend_Loader_Autoloader_Interface {
static protected $php_thumb_classes = array(
'PhpThumb' => 'PhpThumb.inc.php',
'ThumbBase' => 'ThumbBase.inc.php',
'PhpThumbFactory' => 'ThumbLib.inc.php',
'GdThumb' => 'GdThumb.inc.php',
'GdReflectionLib' => 'thumb_plugins/gd_reflection.inc.php',
);
/**
* Autoload a class
*
* #param string $class
* #return mixed
* False [if unable to load $class]
* get_class($class) [if $class is successfully loaded]
*/
public function autoload($class) {
$file = APPLICATION_PATH . '/../library/PhpThumb/' . self::$php_thumb_classes[$class];
if (is_file($file)) {
require_once($file);
return $class;
}
return false;
}
}
i saved this file as PhpThumb.php in the loaders/Autoloader folder. Then added this line to the bootstrap file:
Zend_Loader_Autoloader::getInstance()->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
But it produces an error saying the class was not found. I am guessing that the 'CustomLoader_PhpThumb.php' needs to be saved somewhere else. Any idea guys ?
Update1:
Bootstrap.php file contents
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoload()
{
$autoLoader=Zend_Loader_Autoloader::getInstance();
$resourceLoader=new Zend_Loader_Autoloader_Resource(array(
'basePath'=>APPLICATION_PATH,
'namespace'=>'',
'resourceTypes'=>array(
'form'=>array(
'path'=>'forms/',
'namespace'=>'Form_'
),
'models'=>array(
'path'=>'models/',
'namespace'=>'Model_'
),
)
));
//return $autoLoader;
$resourceLoader->addResourceType('loader', 'loaders/', 'My_Loader_');
$autoLoader->pushAutoloader($resourceLoader);
$autoLoader->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
}
}
?>
I'm also using PhpThumb and the same autoloader. In my case however it is called My_Loader_Autoloader_PhpThumb and is located in APPLICATION_PATH . '/loaders/Autoloader/PhpThumb.php.
In my Bootstrap.php, first I load the loaders path to the Zend_Loader_Autoloader and then I push the My_Loader_Autoloader_PhpThumb autoloader as follows:
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
));
$resourceLoader->addResourceType('loader', 'loaders/', 'My_Loader_');
$autoLoader->pushAutoloader($resourceLoader);
$autoLoader->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
Hope this will help.
PhpThumb.php should be saved to library/CustomLoader folder, and you should setup autoloader for this class also, for example in application.ini:
autoloaderNamespaces[] = "CustomLoader_"
or in Bootstrap.php:
$autoloader->registerNamespace('CustomLoader_');
I couldn't try, I hope it works!
I did it in another way, long more easy, without any autoloader, just using "My".
1.- Create a phpThumbFolder with all the files of the library into project/library/My/PhpThumb
2.- Create a file named PhpThumbFactory.php into that folder with the following content:
require_once('ThumbLib.inc.php');
class My_PhpThumb_PhpThumbFactory
{
public static function create ($filename = null, $options = array(), $isDataStream = false)
{
return PhpThumbFactory::create($filename, $options, $isDataStream);
}
}
3.- Enjoy:
public function editimageAction()
{
//rutaImg is the physical path to my images defined in application.ini
$rutaImg = Zend_Registry::get('config')->rutaImg. "test.jpg";
//Call to our "gateway" class
$thumb = My_PhpThumb_PhpThumbFactory::create($rutaImg);
//Resize
$thumb->adaptiveResize(20, 20);
//Show
$thumb->show();
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
}
I hope it can help anyone ;)
P.D. The "gateway" class is to avoid modifying any code of the library, so any possible update is easy.