So I'm working on a basic file upload system that for the most part seems to be working. Most files go through perfectly and upload without a hitch, but for some reason, other files do not and I get the following error:
This isn't a permissions error as it does work for some files - I don't believe it to be a filesize or filetype issue either.
My upload method is as follows:
$file = Input::file('photo');
$destinationPath = 'user_img/';
$extension = $file->getClientOriginalExtension();
$rand = str_random(12);
$filename = 'usr_'. Auth::user()->id . '_str=' . $rand . '_file='. Crypt::encrypt($file->getClientOriginalName()) .'.'. $extension;
$upload_success = $file->move($destinationPath, $filename);
I'm not finding any solution on the web, and I can't figure out why it's throwing this exception. Any ideas?
I don't want to count all characters in the filename in the screenshot, but there could be an issue with the length of your file name. Wikipedia Filename - Length Restrictions
In my case, this was the issue: using reserved characters in a file name.
This is how i was getting the file name:
$photo_name = "User_".md5($user->id).'_'.date('Y-m-d H:i:s').".$ext";
This would mean that the eventual file name would have characters like -,: and _. On reading this Wikipedia article https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words , i realised that the : (colon) is a reserved character and once i got rid of it (by amending the timestamp section to date('Ymd_His'), the error was gone and the upload was successful.
Ah damn, it seems as my filelengths were over 255 characters and thus the filesystem wasn't liking it. I've changed from Crypt to MD5 and the issue is now resolved.
Something similar happened to me, the context was this: through the view I was loading a file through an input. When I tried to save the file to a folder, I got this error. I use laravel 9 with livewire.
In the end I just had to use the methods provided by liveware:
$filename = time() . $this->documento->getClientOriginalName();
$this->documento->storeAs('documents', $filename, 'public');
Fuentes: https://laravel-livewire.com/docs/2.x/file-uploads
Related
Helo.
I have a question. Just now, when I tried to delete a picture using only unlink without the # symbol, it returned the "unlink is a directory" error. What is the reason that causes it? I received an advice that using the symbol # to the unlink is a bad practice, but somehow this is the method that works.
$file = $request->file('image');
if($file->getSize() < 2048000){
$path = storage_path('app/public/' . $event->img);
if (file_exists($path)) {
unlink($path);
}
$filename = Str::uuid() . "." . $file->getClientOriginalExtension();
$event->img = $request->image->storeAs('events', $filename, 'public');
}
// Create and save post with validated data
$event->save();
In the for loop, it is possible that one of the image names is empty and unlink is trying to delete a directory instead of file. unlink is only used to delete files and not directories. If you try to delete a directory using unlink, you will get an error. See the documentation for unlink.
The file_exists function checks whether a file or directory exists. Since you want to check if file exists and not directory, then you should use the is_file function instead of file_exists. See the documentation for is_file.
all the idea i need to be sure that the file doesn't saved more than one time and don't lose any file because if tow files get the same (md5) the second file will not saved
(my goal don't save the same file Twice on hard disk)
In other words,
if one user upload image and after that another user upload the same image i need to don't save the the second image because it's already exist in the hard disk all of this because
i need to save space on my hard disk
this is my code it works fine
$targetFolder = '/test/uploadify/uploads'; // Relative to the root
$tempFile = $_FILES['Filedata']['tmp_name'];
$targetPath = $_SERVER['DOCUMENT_ROOT'] . $targetFolder;
$myhash = md5_file($_FILES['Filedata']['tmp_name']);
$temp = explode(".", $_FILES['Filedata']['name']);
$extension = end($temp);
$targetFile = rtrim($targetPath,'/') . '/' .$myhash.'.'.$extension;
if(file_exists($targetFile)){
echo 'exist';
}
// Validate the file type
$fileTypes = array('jpg','jpeg','gif','png'); // File extensions
$fileParts = pathinfo($_FILES['Filedata']['name']);
if (in_array($fileParts['extension'],$fileTypes)) {
move_uploaded_file($tempFile,$targetFile);
}
else {
echo 'Invalid file type.';
}
thanks for all of you
Well, of course you can do this, in fact this is the way I use to avoid file duplications (and I mean not having two files wit the same content and not just silly name collision).
If you are worried about collisions, then you might take a look at sha1_file:
http://es1.php.net/manual/en/function.sha1-file.php
What are the chances that two messages have the same MD5 digest and the same SHA1 digest?
I've been using the md5 approach the way you are suggesting here for image galleries and it works just fine.
Another thing to take care about is the time it takes to calculate the hash, the more complex the hash, the more time it needs, but I'm talking about processing really big batches.
If I understand your question correctly your goal is just to generate unique file names. If so, there is no point in reinventing the wheel - every hash function with fixed output length is going to have collisions - just use built in tempnam function.
Manual states:
Creates a file with a unique filename, with access permission set to 0600, in the specified directory. If the directory does not exist, tempnam() may generate a file in the system's temporary directory, and return the full path to that file, including its name.
Following should work well enough:
$targetDirectory = $_SERVER['DOCUMENT_ROOT'] . '/test/uploadify/uploads';
$uploadedFile = $_FILES['Filedata']['tmp_name'];
$targetFile = tempnam($targetDirectory, '');
move_uploaded_file($uploadedFile, $targetFile);
You could always add the systems current time in milliseconds to the filename. That plus the md5, would have a very unlikely chance of returning the same values.
It's very small, but the chance is there. You can read more here and here
I suggest you add a salt to the end of the filename to make it practically impossible for files to conflict(You should put the salt in a different md5 function though)
$salt = md5(round(microtime(true) * 1000));
$hash = md5_file($_FILES['Filedata']['tmp_name']);
$targetFile = rtrim($targetPath,'/') . '/' .$hash.$salt.'.'.$extension;
You should then insert the filename in a database so you can access it later.
I am trying to move an image file previously uploaded into a tmp directory to a permament location. I have used this tutorial as a starting point:
maxoffsky.com/code-blog/uploading-files-in-laravel-4/
I have amended the code as I am uploading the files earlier and accessing them later through a url provided by the form. The code below shows what I am doing:
$form_element = "image_1"; // hidden form element containing the tmp location
$tmp_path = $form_data[$form_element]; // gets the tmp url from hidden element
$file = fopen($tmp_path, 'r'); // opens the file
$destinationPath = 'images/adverts/'.$advert->id; // specifies a new folder
$filename = $file->getClientOriginalName(); // retrieves the name of the file
$upload_success = $file->move($destinationPath, $filename); // moves the file to its new location
The problem I am having is that in the tutorial, they use the code:
$file = Input::file('file'); // Laravel syntax for $_POST['file']
This retrieves the file from the html form itself. From there the functions $file->getClientOriginalName() and $file->move() work correctly.
However, in mine, as my form doesnt provide an actual file, just a link to one, I am trying to access the file and perform the same operations, however I get this error:
Call to a member function getClientOriginalName() on a non-object
I dont think that fopen() is returning the same type as $_POST['file'] hence it isnt working.
How can I make my code work?
Many thanks
I had the same issue, just add in the Form::open in array the enctype:
enctype='multipart/form-data'
and your problems are solved! I have forgotten it and banging my head to the wall after that I started harder to bang it when I saw it.
PS. You have a little misconception. Input::file('file') it's not syntax for $_POST['file'], but for $_FILES['file']
I'm trying to upload some photos and handle this with the build in Laravel functions. But I can't for the life of me figure out how to do this properly. I have been able to actually upload something, but I've run into a few problems. This is the code I have right now:
If looked at the documentation, and found this function: $file = Input::file('photo'); I've used this function, and what the content of $file becomes is an instance of Symfony\Component\HttpFoundation\File\UploadedFile, which, as the documentation tells us, "extends the PHP SplFileInfo class and provides a variety of methods for interacting with the file." http://laravel.com/docs/4.2/requests#files
Then I used this function Input::file('photo')->move($destinationPath); which should but the file in the desired folder on the server. And it did. But now comes the problem. Now all uploaded files have a filename like phpgoJnLc, and without an extension.
I've looked at the functions available from SplFileInfo and tried getExtension which give me an empty string and getFilename which also gives me something like phpgoJnLc.
Then I looked around on the internet and found a few part of code from Laravel 3, where they did something like this:
$filename = Str::random(20) .'.'. File::extension(Input::file('photo.name'));
But the result of this is give me only the result from Str::random(20) followed by a dot. Again, no file extension.
So, what am I doing wrong? How to upload a file with Laravel 4?
Looking in that same class file I see a getClientOriginalName() function...
$file = Input::file('photo');
$file->move($destinationPath,$file->getClientOriginalName());
... which ais ssuming you want to keep the original name your client sets... which could be hazardous, do some safety checks on it would be my advice. Getting the extensionname only is done with ->getClientOriginalExtension(), so you could also only save that part & add a random string before that in the second argument of the move() function.
This worked for me, especially when you want to change the name of the uploaded image:
$filename = 'New_Name'.'.'.Input::file('photo')->getClientOriginalExtension();
You can also generate a name for the file with the original file extension like so:
$filename = Str::random(20) . '.' . Input::file('image')->guessExtension();
if you try to use the following in Laravel 4:
$filename = Str::random(20) .'.'. File::extension(Input::file('photo.name'));
you will get this error:
'Call to undefined method Illuminate\Filesystem\Filesystem::guessExtension()'
I already looked at this StackOverflow question and it didn't help (similarly titled).
I'm passing an image in from my Android application. If I type
$file = fopen('test.jpg', 'wb');
It works correctly and the image uploads; however, I want to allow for multiple uploads from android phones, so I want to randomize the name of the .jpg file so that I can save each new upload as a different name. I was trying this below:
$destination = time() + rand(1, 1000) . ".jpg";
$url_destination = "/project_images/" . $destination;
$file = fopen($url_destination, 'wb');
fwrite($file, $binary);
fclose($file);
It doesn't write the file to the server, however. I tried different variations of the URL there - with 'project_images/', '/project_images/', even trying the full URL (which the aforementioned StackOverflow post corrected me on), and I still can't get it to write.
The permissions of the project_images folder are set to allow files to be written to it. Any ideas?
Your problem is "/project_images" which is a wrong absolute path.
For it to work change it to "project_images/" or dirname(__FILE__).'/project_images/'.
For those who use XAMPP on Windows: use DIRECTORY_SEPARATOR instead /
dirname(__FILE__).DIRECTORY_SEPARATOR.'project_images'.DIRECTORY_SEPARATOR