I am trying to generate a thumbnail of the PDF I upload in laravel the thumbnail should be the first page of the PDF. Right now I am manually uploading an image to make the thumbnail like this:
if (request()->has('pdf')) {
$pdfuploaded = request()->file('pdf');
$pdfname = $request->book_name . time() . '.' . $pdfuploaded->getClientOriginalExtension();
$pdfpath = public_path('/uploads/pdf');
$pdfuploaded->move($pdfpath, $pdfname);
$book->book_file = '/uploads/pdf/' . $pdfname;
$pdf = $book->book_file;
}
if (request()->has('cover')) {
$coveruploaded = request()->file('cover');
$covername = $request->book_name . time() . '.' . $coveruploaded->getClientOriginalExtension();
$coverpath = public_path('/uploads/cover');
$coveruploaded->move($coverpath, $covername);
$book->card_image = '/uploads/cover/' . $covername;
}
This can be tedious while entering many data I want to generate thumbnail automatically. I searched many answers but I am not able to find laravel specific. I tried to use ImageMagic and Ghost script but I couldn't find a solution and proper role to implement.
Sorry, can't comment yet!
You can use spatie/pdf-to-image to parse the first page as image when file is uploaded and store it in your storage and save the link in your database.
First you need to have php-imagick and ghostscript installed and configured. For issues with ghostscript installation you can refer this. Then add the package composer require spatie/pdf-to-image.
As per your code sample:
if (request()->has('pdf')) {
$pdfuploaded = request()->file('pdf');
$pdfname = $request->book_name . time() . '.' . $pdfuploaded->getClientOriginalExtension();
$pdfpath = public_path('/uploads/pdf');
$pdfuploaded->move($pdfpath, $pdfname);
$book->book_file = '/uploads/pdf/' . $pdfname;
$pdf = $book->book_file;
$pdfO = new Spatie\PdfToImage\Pdf($pdfpath . '/' . $pdfname);
$thumbnailPath = public_path('/uploads/thumbnails');
$thumbnail = $pdfO->setPage(1)
->setOutputFormat('png')
->saveImage($thumbnailPath . '/' . 'YourFileName.png');
// This is where you save the cover path to your database.
}
Related
I need assistance to more understand the concept so I can become a better developer. I want to learn how to refactor the code and erase all duplications.
What's the best practices for image uploads? Renaming them correctly?
I have a block of code that handles two attachments:
if( $request->hasFile('LFImage') ) {
$destination = public_path('app/lostFound/lostItems' . $lostFound->LFImage);
if( File::exists($destination) )
{
File::delete($destination);
}
$file = $request->file('LFImage');
$extension = $file->getClientOriginalExtension();
$filename = $lostFound->LFNumber . '-' . $lostFound->lostItem . '.' . $extension;
$file->move('app/lostFound/lostItems', $filename);
$lostFound->LFImage = $filename;
}
if( $request->hasFile('handoverStatement') ) {
$destination = public_path('app/lostFound/handoverStatements' . $lostFound->handoverStatement);
if( File::exists($destination) )
{
File::delete($destination);
}
$file = $request->file('handoverStatement');
$extension = $file->getClientOriginalExtension();
$filename = $lostFound->lostItem . '-' . $lostFound->LFNumber . '.' . $extension;
$file->move('app/lostFound/handoverStatements', $filename);
$lostFound->handoverStatement = $filename;
}
They're exactly the same except with the upload directory.
How can I make it as a one code block across the entire application with changeable file name and location depending on the form?
Some file names require random strings, how can I "Edit" the random string to the file that was uploaded?
Best practice when uploading and storing files in Laravel is using Storage.
It has all needed methods to work with files, you can save the file like this:
use Illuminate\Support\Facades\Storage;
Storage::put('images/', $request->file('LFImage'));
In the documentation provided above, you can find other examples like renaming and moving files
In order to access these files from web as well, you can use the command php artisan storage:link, which creates a symbolic link to storage folder in your public folder. After you create the symbolic link, you can generate URL to the file like this:
asset('storage/test.txt')
To avoid duplications, you can create a function in your controller to create a file. You will then just call this function with different files to keep the file creation code in one place.
you can simply write this
if ($request->hasFile('logo')) {
deleteImageFromDirectory(setting('logo'), "Settings");
$data['logo'] = uploadImageToDirectory( $request->logo , "Settings");
}
and define uploadImageToDirectory function in your helper functions or create a trait
function uploadImageToDirectory($imageFile, $directory = '' ){
$imageName = $imageFile->getClientOriginalName(); // Set Image name
$imageFile->storeAs("/Images/$directory", $imageName, 'public');
return $imageName;
}
so i can upload my photo from my Android app fine to /var/www/html/ProductPhotos but when i want to get the name of the Product and use that as the name of the new directory and image name then its not working. I create the new directory and /var/www/html/ProductPhotos with 777 permissions (even though its super bad) but for now its what i need. here's my PHP code:
<?php
$ProductAccountName = $_POST['ProductAccountName'];
$ProductName = $_POST['ProductName'];
$ProductImage = $_POST['EncodedImage'];
$NewDirectory = "/var/www/html/ProductPhotos/" . $ProductAccountName;
mkdir($NewDirectory, 0777, true);
//$DecodedProductImage = base64_decode("$ProductImage");
//$ProductName = $ProductName .".JPG";
file_put_contents("/var/www/html/ProductPhotos/" . $ProductAccountName, $ProductName . ".JPG", $DecodedProductImage);
?>
You're using a comma instead of a period. And you're missing a slash.
file_put_contents("/var/www/html/ProductPhotos/" . $ProductAccountName . "/" . $ProductName . ".JPG", $DecodedProductImage);`
See the file_put_contents docs.
You may want to be put into place some checks to make sure the user doesn't use relative paths(using ../ as part the ProductAccountName, for example). Just be careful of the user using this to do malicious things.
I write a edit function to update news's info, delete previous image from web root and insert new image:
code is below:
if(unlink($data['News']['image_url']['tmp_name'], WWW_ROOT . 'media/' . $data['News']['image_url']['name'])) //delete image from root and database
{
echo 'image deleted.....'; //success message
}
I can't delete old image and insert new image,how can i correct my function ?
Here your data can not find existing data. use this code
$data1 = $this->News->findById($newsid);
$this->request->data = $data1;
$directory = WWW_ROOT . 'media';
if(unlink($directory.DIRECTORY_SEPARATOR.$data1['News']['image_url']))
{
echo 'image deleted.....';
}
Pass filepath as first argument of unlink():
unlink(WWW_ROOT . 'media/' . $data['News']['image_url']['name'] . '/' . $data['News']['image_url']['tmp_name']);
Also make sure that you have proper permissions to perform this operation in directory containing image.
I can't get the picture to display/show when viewing, although the files are already stored in the database (table 'menu') http://i.imgur.com/wo1w90H.png. Also when I upload the images all at once, their file name would change automatically. I don't know how and why this happens. I use array to upload multiple images.
if (isset($_POST["Submit"])) {
--some code here--
if (isset($_POST["id_list"])) {
// if id list available
foreach($_POST["id_list"] AS $id) {
--some code here--
/* Handle file upload */
if ($_FILES['upload']['error'][$id] == 'UPLOAD_ERR_OK') {
$path = "images/newmenu/";
$path_parts = pathinfo($_FILES["upload"]["name"][$id]);
$extension = $path_parts['extension'];
$picture = md5(uniqid()) . "." . $extension;
if (move_uploaded_file($_FILES['upload']['tmp_name'][$id], $path . "/" . $picture)) {
$update = " UPDATE menu
SET MenuPicture='$picture'
WHERE MenuID=$id";
$mysqli->query($update) or die(mysqli_error($mysqli));
}
}
}
}
}
}
Below is the form and yes it does include enctype="multipart/form-data"
<input type="file" multiple name="upload[' . $id . ']" value="' . $record["MenuPicture"] . '">
Filename changes because you are generating it this way
$picture = md5(uniqid()) . "." . $extension;
uniqid() is based on current time and hashing it will cause the filename to change everytime
When I upload the images all at once, their file name would change automatically
It was due to this:
$picture = md5(uniqid()) . "." . $extension;
// And later
move_uploaded_file($_FILES['upload']['tmp_name'][$id], $path . "/" . $picture)
Basically, you are moving your uploaded file to a new filename for your image file, which is generated using uniqid() and hashed with md5(), with the file extension appended at the end.
I can't get the picture to display/show when viewing
How are you trying to display the picture? Is it from web browser, or you go straight to the directory and open from there? What error(s) did you get, if any?
Actually, have you tried to go to the directory and see whether the file is created inside the images/newmenu/ directory?
Also, for the target upload directory, you might want to append it with $_SERVER['DOCUMENT_ROOT'] so that the target directory is not dependent on where your script is located, but it's always based on the root.
By the way, you might know already, but there is an entry in PHP manual page on uploading multiple files
Long time reader, first time poster. I know just enough about php to be dangerous and this is my first BIG project using it.
Some background:
I have over 1 million (yes, million) .html files that were generated from an old news gathering program. These .html files contain important archive information that needs to be searched on daily basis. I have yet to get to other servers which might very well have more so 2-3 million+ is not out of the question.
I am taking these .html files and transferring them into a mysql database. At least, so far, the code has worked wonderfully with several hundred test files. I'll attach the code at the end.
The problem starts when the .html files are archived, and it's a function of the box generating the archive which cannot be changed, is the files go into folders. They are broken down like this
archives>year>month>file.html
so an example is
archives>2002>05may>lots and lots of files.html
archives>2002>06june>lots and lots of files.html
archives>2002>07july>lots and lots of files.html
With help and research, I wrote code to strip the files of markup that includes html2text and simple_html_dom and put the information from each tag in the proper fields in my database, which works great. But ALL of the files need to be moved to the same directory for it to work. Again, over a million and possibly more for other severs takes a REALLY long time to move. I am using a batch file to robocopy the files now.
My question is this:
Can I use some sort of wildcard to define all of the subdirectories so I don't have to move all of the files and they can stat in their respective directories?
Top of my code:
// Enter absolute path of folder with HTML files in it here (include trailing slash):
$directory = "C:\\wamp1\\www\\name\\search\\files\\";
The subdirectories are under the files directory.
In my searches for an answer, I have seen "why would you want to do that?" or other questions asking about .exe files or .bat files in the directories and how it could be dangerous so don't do it. My question is just for these html files so there is nothing being called or running and no danger.
Here is my code for stripping the html into the database. Again, works great, but I would like to skip the step of having to move all of the files into one directory.
<?php
// Enter absolute path of folder with HTML files in it here (include trailing slash):
$directory = "C:\\wamp1\\www\\wdaf\\search\\files\\";
// Enter MySQL database variables here:
$db_hostname = "localhost";
$db_username = "root";
$db_password = "password";
$db_name = "dbname";
$db_tablename = "dbtablename";
/////////////////////////////////////////////////////////////////////////////////////
// Include these files to strip all characters that we don't want
include_once("simple_html_dom.php");
include_once("html2text.php");
//Connect to the database
mysql_connect($db_hostname, $db_username, $db_password) or trigger_error("Unable to connect to the database host: " . mysql_error());
mysql_select_db($db_name) or trigger_error("Unable to switch to the database: " . mysql_error());
//scan the directory and look for all the htmls files
$files = scandir($directory);
for ($filen = 0; $filen < count($files); $filen++) {
$html = file_get_html($directory . $files[$filen]);
// first check if $html->find exists
if (method_exists($html,"find")) {
// then check if the html element exists to avoid trying to parse non-html
if ($html->find('html')) {
//Get the filename of the file from which it will extract
$filename = $files[$filen];
//define the path of the files
$path = "./files/";
//Combine the patha and filename
$fullpath = $path . $filename;
// Get our variables from the HTML: Starts with 0 as the title field so use alternate ids starting with 1 for the information
$slug = mysql_real_escape_string(convert_html_to_text($html->find('td', 8)));
$tape = mysql_real_escape_string(convert_html_to_text($html->find('td', 9)));
$format0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 10)));
$time0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 11)));
$writer = mysql_real_escape_string(convert_html_to_text($html->find('td', 12)));
$newscast = mysql_real_escape_string(convert_html_to_text($html->find('td', 13)));
$modified = mysql_real_escape_string(convert_html_to_text($html->find('td', 14)));
$by0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 15)));
$productionCues = mysql_real_escape_string(convert_html_to_text($html->find('td', 16)));
$script = mysql_real_escape_string(convert_html_to_text($html->find('td', 18)));
// Insert variables into a row in the MySQL table:
$sql = "INSERT INTO " . $db_tablename . " (`path`, `fullpath`, `filename`, `slug`, `tape`, `format0`, `time0`, `writer`, `newscast`, `modified`, `by0`, `productionCues`, `script`) VALUES ('" . $path . "', '" . $fullpath . "', '" . $filename . "', '" . $slug . "', '" . $tape . "', '" . $format0 . "', '" . $time0 . "', '" . $writer . "', '" . $newscast . "', '" . $modified . "', '" . $by0 . "', '" . $productionCues . "', '" . $script . "');";
$sql_return = mysql_query($sql) or trigger_error("Query Failed: " . mysql_error());
}
}
}
?>
Thanks in advance,
Mike
Just wanted to update this post with a answer to my question that works quite well. With some help, we found that scandir used recursively to create an array would work.
I thought I'd post this so if anyone else was looking to do something similar, they would be able wouldn't have to look far! I know I like to see answers!
The code is from the second user-contributed note here with a few modifications: http://php.net/manual/en/function.scandir.php
so in my code above, I replaced
//scan the directory and look for all the htmls files
$files = scandir($directory);
for ($filen = 0; $filen < count($files); $filen++) {
$html = file_get_html($directory . $files[$filen]);
with
function import_dir($directory, $db_tablename) {
$cdir = scandir($directory);
foreach ($cdir as $key => $value)
{
if (!in_array($value,array(".","..")))
{
if (is_dir($directory . DIRECTORY_SEPARATOR . $value))
{
// Item in this directory is sub-directory...
import_dir($directory . DIRECTORY_SEPARATOR . $value,$db_tablename);
}
else
// Item in this directory is a file...
{
$html = file_get_html($directory . DIRECTORY_SEPARATOR . $value);
and then for the filenames, replaced
//Get the filename of the file from which it will extract
$filename = $files[$filen];
//define the path of the files
$path = "./files/";
//Combine the patha and filename
$fullpath = $path . $filename;
with
//Get the filename of the file from which it will extract
$filename = mysql_real_escape_string($value);
//define the path of the files
$path = mysql_real_escape_string($directory . DIRECTORY_SEPARATOR);
//Combine the patha and filename
$fullpath = $path . $value;
Thanks to those who answered!
Mike
I'm not sure how long it would take before your PHP query times out, but there is an inbuilt function RecursiveDirectoryIterator which sounds like it might do the trick for you.