Laravel 5.1 file upload unique name - php

My controller code where i store the file name into a database table and also moving the file to a folder.
The issue is that i am storing the original name of a file in database table, in contrast i am moving files with uniqueid() and time() . It will arise issues in future. because in database table file name and moved file are with different names.
What i want is to store the file name into database table and move the file to folder with with uniqueid() and time().
Code :
if(Input::hasFile('profile_pic')){
$pic = Input::file('profile_pic');
$mobile->photo1 = $pic[0]->getClientOriginalName();
$mobile->photo2 = $pic[1]->getClientOriginalName();
$mobile->photo3 = $pic[2]->getClientOriginalName();
$mobile->photo4 = $pic[3]->getClientOriginalName();
$mobile->photo5 = $pic[4]->getClientOriginalName();
foreach ($pic as $k=>$file){
if(!empty($file)){
$file->move(public_path() . '/uploads/', time() . uniqid() . '-' . $k . '-laptop');
}
}
}

You will need to store the destination path into a variable and then reuse it to move the file and to store its value in the database
if(Input::hasFile('profile_pic')){
$pic = Input::file('profile_pic');
$mobile->photo1 = $pic[0]->getClientOriginalName();
$mobile->photo2 = $pic[1]->getClientOriginalName();
$mobile->photo3 = $pic[2]->getClientOriginalName();
$mobile->photo4 = $pic[3]->getClientOriginalName();
$mobile->photo5 = $pic[4]->getClientOriginalName();
foreach ($pic as $k=>$file){
if(!empty($file)){
$destinationPath = public_path() . '/uploads/', time() . uniqid() . '-' . $k . '-laptop';
$file->move($destinationPath);
// and you may store the path here to the database
// like yourObject->filePath = $destinationPath;
// yourObject->save();
}
}
}

Related

Losing variable value when trying to copy file using mailReader.php

I'm using the mailReader script found here: https://github.com/stuporglue/mailreader
I am trying to copy the file(s) after upload to another folder.
The file(s) upload correctly to the folder where the script resides.
When I try to run a copy command, the filename variable is empty.
Here is the portion of the code I am working with: The last three lines are what I added.
private function saveFile($filename,$contents,$mimeType = 'unknown'){
$filename = preg_replace('/[^a-zA-Z0-9_-]/','_',$filename);
$unlocked_and_unique = FALSE;
while(!$unlocked_and_unique){
// Find unique
$name = time() . "_" . $filename;
$name = substr_replace($name,".pdf",-4); // added 1-19-2016
while(file_exists($this->save_directory . $name)) {
$name = time() . "_" . $filename;
$name = substr_replace($name,".pdf",-4);
}
// Attempt to lock
$outfile = fopen($this->save_directory.$name,'w');
if(flock($outfile,LOCK_EX)){
$unlocked_and_unique = TRUE;
}else{
flock($outfile,LOCK_UN);
fclose($outfile);
}
}
fwrite($outfile,$contents);
fclose($outfile);
if (copy($this->save_directory.$name, "/attachments/" . TRANS_ID . "/". $name)) {
unlink( $this->save_directory.$name );
}
I receive confirmation by email that the file(s) are uploaded, then another email with the error message.
Warning: copy(/attachments/W7652222-546/1453406138_residential-print_from_td.pdf): failed to open stream: No such file or directory in /home/myhost/public_html/mailreader/mailReader.php on line 224
224 being the line number of my added code.
The source filename is missing from in front of /attachments...
Anyone have any thoughts?
$name is defined in the while loop and may not be accessible on the upper scopes my suggestion is to change your code to this:
private function saveFile($filename,$contents,$mimeType = 'unknown'){
$filename = preg_replace('/[^a-zA-Z0-9_-]/','_',$filename);
$unlocked_and_unique = FALSE;
$name = '';
while(!$unlocked_and_unique){
// Find unique
$name = time() . "_" . $filename;
$name = substr_replace($name,".pdf",-4); // added 1-19-2016
while(file_exists($this->save_directory . $name)) {
$name = time() . "_" . $filename;
$name = substr_replace($name,".pdf",-4);
}
// Attempt to lock
$outfile = fopen($this->save_directory.$name,'w');
if(flock($outfile,LOCK_EX)){
$unlocked_and_unique = TRUE;
}else{
flock($outfile,LOCK_UN);
fclose($outfile);
}
}
fwrite($outfile,$contents);
fclose($outfile);
if (copy($this->save_directory.$name, "/attachments/" . TRANS_ID . "/". $name)) {
unlink( $this->save_directory.$name );
}
I hope this solves your problem
I ended up defining a constant of email_id in the private function saveToDb, then running a script after everything else is finished to query the table using the email_id and looping through the records moving the files.

Laravel 5.1 file upload, File's same name for folder and database

My controller code where i store the file name into a database table and also moving the file to a folder.
The issue is that i am storing the original name of a file in database table, in contrast i am moving files with uniqueid() and time() . It will arise issues in future. because in database table file name and moved file are with different names.
if(Input::hasFile('profile_pic')){
$pic = Input::file('profile_pic');
$mobile->photo1 = $pic[0]->getClientOriginalName();
$mobile->photo2 = $pic[1]->getClientOriginalName();
$mobile->photo3 = $pic[2]->getClientOriginalName();
$mobile->photo4 = $pic[3]->getClientOriginalName();
$mobile->photo5 = $pic[4]->getClientOriginalName();
foreach ($pic as $k=>$file){
if(!empty($file)){
$file->move(public_path() . '/uploads/', time() . uniqid() . '-' . $k . '-laptop');
}
}
}
You can try to use something like that:
if(Input::hasFile('profile_pic')){
$pic = Input::file('profile_pic');
foreach ($pic as $k=>$file){
if(!empty($file)){
$temp = $k+1;
$mobile->photo.$temp = time() . uniqid() . '-' . $k . '-laptop';
$file->move(public_path() . '/uploads/', $mobile->photo.$temp);
}
}
}
You can store both names in your database. Store one as original_name and one as generated_name for example.
And you can serve the file with the original name by retrieving it from the database if you want to let your users download it. It should look like this:
$photo = Photo::find(1);
return response()->download($photo->generated_filename, $photo->filename);

Setting the directory to include subdirectories using html2text

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.

Check if file exist before renaming file upon upload

I need help with adding the feature to check whether a file exists when uploading.
This is how the upload.php code looks like for uploading:
$file_name = $HTTP_POST_FILES['ljudfil']['name'];
$random_digit=rand(0000,9999);
$mp3 ='.mp3';
$pdf ='.pdf';
$datum = date('Ymd');
$new_file_name=$random_digit.$file_name;
$target_path1 = $target_path . $orgnr . '_' . $gsm . $pdf;
$target_path3 = $target_path . 'AC' . $datum . $new_file_name . $mp3;
$target_path11 = $target_path4 . $orgnr . '_' . $gsm . $pdf;
$target_path33 = $target_path4 . 'AC' . $datum . $new_file_name . $mp3;
$targetljudfilftp = 'AC' . $datum . $new_file_name . $mp3;
move_uploaded_file($_FILES['avtalsfil1']['tmp_name'], $target_path1);
move_uploaded_file($_FILES["ljudfil"]["tmp_name"], $target_path3);
$sql = "INSERT INTO affarer (tid, cid, orgnr, ljudfilftp) VALUES
(CURDATE(),'$date','$cid','$orgnr', '$targetljudfilftp')";
As you can see, it renames the uploaded file including a random number.
Sometimes, it happens that it renames the file to a number that already exists.
When that happens, it overwrites the previous file on my server.
So, how can I add a function to check whether the target name exists before it is used for renaming?
You can use
if (file_exists($target_path1))
to verify whether a file exists.
You would do better, though, to change strategy and employ tempnam:
$target_path = tempnam ($target_path, 'AC' . $datum . $file_name . $mp3)
This will create a file such as "AC_2012_Anacreon.mp3_xTfKxy" but you have the guarantee of it being unique, while even using file_exists would expose you to the risk of a concurrency collision.
Of course the file no longer has a .mp3 extension, so you have to take it into account when you scan the directory and supply files for download.
A still not secure, but maybe easier way is this:
for(;;)
{
$newname = // some strategy to generate newname, including a random
if (!file_exists($newname))
touch($newname);
if (!filesize($newname))
break;
}
or you can use a lock file to guarantee no concurrency (and therefore, that file_exists will return the truth and it will stay the truth):
$fp = fopen('.flock', 'r+');
if (flock($fp, LOCK_EX))
{
for(;;)
{
$newname = // some strategy to generate newname, including a random
if (!file_exists($newname))
{
// this creates the file uniquely for us.
// all other writers will find the file already there
touch($newname);
}
}
flock($fp, LOCK_UN);
}
else
die("Locking error");
fclose($fp);
// $newname is now useable.
Use the file_exists builtin function.
You could change the way your random digists are created by using (for example) a time based method
$random_digit = microtime(TRUE);
You can use as below
$random_digit = time();
Instead off using 'rand' function which can generate a duplicated number, you can use 'uniqid'php function, it returns a unique id ( http://www.php.net/manual/en/function.uniqid.php ).
If you still want to use the 'rand' you can use 'file_exists' function with the generated file name as param ( http://www.php.net/manual/en/function.file-exists.php ), but if a file exists you must regenerate the file name, so you will iterate each time the file exists.
At last, think to use full time date('Ymdhis') format instead off date('Ymd'), it's also better to use timestamp by calling time() function ( http://www.php.net/manual/en/function.time.php )
Anas,
if (file_exists($random_digit)) {
$random_digit = rand(0000,9999);
}

Save 'Username' as Filename

I wonder whether someone could help me please.
I'm using Image Uploader from Aurigma, and to save the uploaded images, I've put this script together.
<?php
//This variable specifies relative path to the folder, where the gallery with uploaded files is located.
//Do not forget about the slash in the end of the folder name.
$galleryPath = 'UploadedFiles/';
require_once 'Includes/gallery_helper.php';
require_once 'ImageUploaderPHP/UploadHandler.class.php';
/**
* FileUploaded callback function
* #param $uploadedFile UploadedFile
*/
function onFileUploaded($uploadedFile) {
$packageFields = $uploadedFile->getPackage()->getPackageFields();
$userid = $packageFields["userid"];
$locationid= $packageFields["locationid"];
global $galleryPath;
$absGalleryPath = realpath($galleryPath) . DIRECTORY_SEPARATOR;
$absThumbnailsPath = $absGalleryPath . 'Thumbnails' . DIRECTORY_SEPARATOR;
if ($uploadedFile->getPackage()->getPackageIndex() == 0 && $uploadedFile->getIndex() == 0) {
initGallery($absGalleryPath, $absThumbnailsPath, FALSE);
}
$dirName = $_POST['folder'];
$dirName = preg_replace('/[^a-z0-9_\-\.()\[\]{}]/i', '_', $dirName);
if (!is_dir($absGalleryPath . $dirName)) {
mkdir($absGalleryPath . $dirName, 0777);
}
$path = rtrim($dirName, '/\\') . '/';
$originalFileName = $uploadedFile->getSourceName();
$files = $uploadedFile->getConvertedFiles();
// save converter 1
$sourceFileName = getSafeFileName($absGalleryPath, $originalFileName);
$sourceFile = $files[0];
/* #var $sourceFile ConvertedFile */
if ($sourceFile) {
$sourceFile->moveTo($absGalleryPath . $sourceFileName);
}
// save converter 2
$thumbnailFileName = getSafeFileName($absThumbnailsPath, $originalFileName);
$thumbnailFile = $files[1];
/* #var $thumbnailFile ConvertedFile */
if ($thumbnailFile) {
$thumbnailFile->moveTo($absThumbnailsPath . $thumbnailFileName);
}
//Load XML file which will keep information about files (image dimensions, description, etc).
//XML is used solely for brevity. In real-life application most likely you will use database instead.
$descriptions = new DOMDocument('1.0', 'utf-8');
$descriptions->load($absGalleryPath . 'files.xml');
//Save file info.
$xmlFile = $descriptions->createElement('file');
$xmlFile->setAttribute('name', $_POST['folder'] . '/' . $originalFileName);
$xmlFile->setAttribute('source', $sourceFileName);
$xmlFile->setAttribute('size', $uploadedFile->getSourceSize());
$xmlFile->setAttribute('originalname', $originalFileName);
$xmlFile->setAttribute('thumbnail', $thumbnailFileName);
$xmlFile->setAttribute('description', $uploadedFile->getDescription());
//Add additional fields
$xmlFile->setAttribute('userid', $userid);
$xmlFile->setAttribute('locationid', $locationid);
$xmlFile->setAttribute('folder', $dirName);
$descriptions->documentElement->appendChild($xmlFile);
$descriptions->save($absGalleryPath . 'files.xml');
}
$uh = new UploadHandler();
$uh->setFileUploadedCallback('onFileUploaded');
$uh->processRequest();
?>
What I'd like to do is replace the files element of the filename and replace it with the username, so each saved folder and associated files can be indentified to each user.
I've added a username text field to the form which this script saves from
I think I'm right in saying that this is line that needs to change $descriptions->save($absGalleryPath . 'files.xml');.
So amongst many attempts I've tried changing this to $descriptions->save($absGalleryPath . '$username.xml, $descriptions->save($absGalleryPath . $username '.xml, but none of these have worked, so I'm not quite sure what I need to change.
I just wondered whether someone could perhaps have a look at this please and let me know where I'm going wrong.
Many thanks
'$username.xml' will be interpreted as $username.xml, you need to use "$username.xml". Single quotes "disable" the variable use inside strings.
What you are tryiing can be a bad idea, as you are making so a username can't contain 'special characters' like "/". Perhaps is not a problem if you aready have a rule that stop "/" being part of a username.

Categories