I have made a form on the front end to upload some images. My idea is to automatically rename all files uploaded into unique id's.
I have looked at the SilverStripe API and I do not see anything about that. UploadField API
Is this possible?
Here is my solution bellow, in Silverstripe 3.X we must extend UploadField with another class. Then copy the ''saveTemporaryFile'' function into it.
Just before ''try'', just have to add :
$ext = array_reverse(explode('.',$tmpFile['name'])); // explode filename into array, reverse array, first array key will then be file extension
$tmpFile['name'] = hash_hmac('sha256', $tmpFile['name'], '12345') . '.' . $ext[0];
Results :
class RandomNameUploadField extends UploadField {
protected function saveTemporaryFile($tmpFile, &$error = null) {
// Determine container object
$error = null;
$fileObject = null;
if (empty($tmpFile)) {
$error = _t('UploadField.FIELDNOTSET', 'File information not found');
return null;
}
if($tmpFile['error']) {
$error = $tmpFile['error'];
return null;
}
// Search for relations that can hold the uploaded files, but don't fallback
// to default if there is no automatic relation
if ($relationClass = $this->getRelationAutosetClass(null)) {
// Create new object explicitly. Otherwise rely on Upload::load to choose the class.
$fileObject = Object::create($relationClass);
}
$ext = array_reverse(explode('.',$tmpFile['name'])); // explode filename into array, reverse array, first array key will then be file extension
$tmpFile['name'] = hash_hmac('sha256', $tmpFile['name'], '12345') . '.' . $ext[0];
// Get the uploaded file into a new file object.
try {
$this->upload->loadIntoFile($tmpFile, $fileObject, $this->getFolderName());
} catch (Exception $e) {
// we shouldn't get an error here, but just in case
$error = $e->getMessage();
return null;
}
// Check if upload field has an error
if ($this->upload->isError()) {
$error = implode(' ' . PHP_EOL, $this->upload->getErrors());
return null;
}
// return file
return $this->upload->getFile();
}
}
Thanks #3dgoo to give me a part of the solution!
I don't now about a API but with some code I was able to do that.
You have two possibilities.
First using database.
Second using only code:
$directory = '/teste/www/fotos/';
$files = glob($directory . '*.jpg');
if ( $files !== false )
{
$filecount = count( $files );
$newid = $filecount+1;
$new_name = "foto_".$newid;
$target_file = $directory."/".$new_name;
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
}
else
{
$new_name = "foto_1";
$target_file = $directory."/".$new_name;
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
}
My example is for jpeg but you can look for hall types.
Related
I've recently created a page on our site where users can upload an image and email it to an email address set up specifically to keep the uploaded documents.
I've tested this myself and it works, with the attachments arriving in gmail as expected.
However, whenever someone from outside uses this feature the attachment in the email is unavailable, or not could not be loaded, when we try to open it.
The code is split between 2 files, a controller and a helper. Here's the code (For the sake of saving some space I've removed all error checks, but in the actual code they are all still in place and not picking up any errors whatsoever):
controller
$helper = [GET HELPER];
/** Upload the file to a temp location so that we can attach it to an email */
$uploader = new Varien_File_Uploader('filename');
$uploader->setAllowedExtensions(array(
'image/jpeg',
'image/jpg',
'image/png',
'application/pdf'
))
->setAllowRenameFiles(true)
->setFilesDispersion(false);
$path = $helper->getFileStorageLocation(); // Will store files in /tmp
if (!is_dir($path))
{
mkdir($path, 0775, true);
}
$uploader->save($path, $_FILES['filename']['name']);
$result = $helper->sendMail($_FILES['filename']['name']);
if ($result)
{
$uploadSuccess = true;
/** Remove the temp file */
unlink($path . DS . $_FILES['filename']['name']);
}
helper
/** Declare variables */
$order = Mage::getModel('sales/order')->load($orderId);
$file_incremented_id = $order->getIncrementId();
$copyTo = $this->getCopyTo();
$copyFrom = $this->getCopyFrom();
$subject = 'proof of upload for ' . $file_incremented_id;
$copyTo = explode(',', $copyTo);
$body = '<span>Please see attachment</span>';
$file = $this->getFileStorageLocation() . DS . $filename; // function receives filename from whatever is calling it
$attachment = file_get_contents($file);
$extension = pathinfo($file, PATHINFO_EXTENSION);
if (!$copyTo)
{
return false;
}
$mail = Mage::getModel('core/email_template');
$mail->setSenderName('Uploader');
$mail->setSenderEmail($copyFrom);
$mail->setTemplateSubject($subject);
$mail->setTemplateText($body);
$mail->getMail()->createAttachment(
$attachement,
Zend_Mime::TYPE_OCTETSTREAM,
Zend_Mime::DISPOSITION_ATTACHMENT,
Zend_Mime::ENCODING_BASE64,
$file_incremented_id . '.' . $extension // Set order number as file name
);
try
{
$mail->send($copyTo);
return true;
}
catch (Exception $e)
{
return false;
}
Can anyone see anything that might be causing the issue, or think of what it might be based on my explanation of the setup?
So the problem, in the end, was filesize. My fault for not posting the $_FILES variable.
I saw it a bit later and the variable had error = 1, meaning that the file's size was larger than what was allowed by the max_upload_filesize in the php.ini
Laravel 4.2 upload file success but not found when I used it
The file uploaded succesfully on the directory I've been specified, but when I want to display it, it return not found, but if I change it to other file name in the same directory, it appears. What's wrong?
here is my code:
app/services/CommonProvider.php
<?php
class CommonProvider{
# simple class to provide static common functions
public static function uploadFiles($filename,$name,$location = 'img/'){
if(Input::hasFile($name)){
$filename .= '.'.Input::file($name)->getClientOriginalExtension();
$filename = $location . $filename;
if(Input::file($name)->move($location, $filename))
return $filename;
return false;
}
return false;
}
}
and here is the updateUser method (for example) from app/services/UserProvider.php
public function updateUser($input, $user_id) {
$validation_messages = $this->validateUser(Input::all(), false);
if ($validation_messages !== true) return $validation_messages;
try {
$insert = $this->user->find($user_id);
$insert->access_level = $input['access_level'];
$insert->email = $input['email'];
$insert->name = $input['name'];
$insert->mobile_no = $input['mobile_no'];
if ($input['password'] != '') $insert->password = Hash::make($input['password']);
if (!isset($input['active_status'])) $insert->active_status = 0;
$insert->save();
$filename = CommonProvider::uploadFiles($insert->id, 'user_image', 'img/user_images/');
if ($filename) {
$insert->user_image = $filename;
}
$insert->save();
return true;
}
catch(Exception $e) {
dd($e);
return false;
}
}
What do I miss?
You shouldn't add path to your filename when moving the file (you can add it when you want to retrieve the file).
$filename = $location . $filename; // remove this line
And I think you need to add absolute path so you will know exactly where the uploaded file is moved to.
In this code I added public_path()
$abslocation = public_path() . '/'. $location;
if(Input::file($name)->move($abslocation, $filename))
return $location . $filename;
I want to create a function which does rename the file and generate a unique name from its name, together with the user id. Below function is working properly but I'm not satisfied, kindly provide me the similar function.
if(is_array($file) and $file['name'] != '')
{
// getting unique file name
$file['name'] = getUniqueFilename($file);
$file_path = $file_root_path.$file['name'];
if(move_uploaded_file($file['tmp_name'], $file_path)){$filename = $file['name'];}
//
if($oldfile != ''){delete_file($file_root_path.$oldfile);}
return $filename;
} // if ends
else
{
return $oldfile;
} // else ends
function getUniqueFilename($file)
{
if(is_array($file) and $file['name'] != '')
{
// getting file extension
$fnarr = explode(".", $file['name']);
$file_extension = strtolower($fnarr[count($fnarr)-1]);
// getting unique file name
$file_name = substr(md5($file['name'].time()), 5, 15).".".$file_extension;
return $file_name;
} // ends for is_array check
else
{
return '';
} // else ends
} // ends
Use php uniqid() to generate unique ids http://php.net/manual/en/function.uniqid.php
function getUniqueFilename($file)
{
if(is_array($file) and $file['name'] != '')
{
// getting file extension
$file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
// getting unique file name
$file_name = uniqid().".".$file_extension;
while(file_exists('PATH_TO_WHERE_YOU_SAVE_FILE/'.$file_name)) {
$file_name = uniqid().".".$file_extension;
}
return $file_name;
} // ends for is_array check
else
{
return '';
} // else ends
} // ends
Take a hash of the file contents, e.g. with sha1_file. That guarantees a unique name for each unique file. If the same file gets uploaded a second time, it will generate the same hash, so you're not even storing duplicates of identical files.
Please use this code, that may help you
<?php
function tempdir($dir, $prefix='', $mode=0700)
{
if (substr($dir, -1) != '/') $dir .= '/';
do
{
$path = $dir.$prefix.mt_rand(0, 9999999);
} while (!mkdir($path, $mode));
return $path;
}
?>
Reference Link: http://www.php.net/manual/en/function.tempnam.php
You could create a filename with an [md5][1] hash salted with current [timestamp][2] and a random number.
Something like:
function getUniqueFilename($file)
{
do {
$name = md5(time().rand().$file['name']);
} while (file_exists($path.$name);
return $name;
}
Being path the folder where you want your file created
i build function to upload zip files but when user upload file two times it didnt delete the first uploaded file but added increment number to the file name (( file.zip,file1.zip,file2.zip,,,etc )
so i want to tell the function when the user uploaded the same file name delete the first file and upload this second file or replace it ... anyone help me how to do that...
/**
* change book source file
*
* #param integer $book_id
*/
public function upload_book_zip($book_id) {
$vars = array();
$vars['upload_path'] = PUBPATH . 'global/modules/bookstore/files/books_source_file/';
$vars['allowed_types'] = 'zip';
$vars['max_size'] = '30720';
$vars['book_id'] = $book_id;
$book = $this->d_book->find_by_id($book_id);
if (isset($_POST['submit'])) {
$file_name = $this->upload($vars);
if ($file_name === NULL) { // error happens while uploading file
$vars['upload_errors'] = $this->upload->display_errors("<p class='notification n-error'>", "</p>");
} else {
$this->d_book->update_one_field($book_id, 'bo_path_zip', $file_name);
$this->session->set_flashdata('success_msg', lang('file_uploaded'));
redirect('bookstore/admin_d_book/');
}
} else {
$vars['upload_errors'] = NULL;
}
if ($book->bo_path_zip) { // load cover image
$vars['file_path'] = base_url() . 'global/modules/bookstore/files/books_source_file/' . $book->bo_path_zip;
} else {
$vars['file_path'] = NULL;
}
$vars['controller_name'] = 'admin_d_book';
$this->view('bookstore/admin/change_zip_file', $vars);
}
/**
*
* #param array $config the configuration array
* #return string
*
*/
private function upload($config) {
$this->load->library('upload', $config);
if (!$this->upload->do_upload("file")) {
return $uploadData['file_name'] = NULL;
} else {
$uploadData = $this->upload->data();
log_message('debug', 'file has been uploaded ok - file name is ' . $uploadData['file_name']);
return $uploadData['file_name'];
}
}
you can do that by adding
$vars['overwrite'] = TRUE;
better check File upload library
Set overwrite to true in the config array you pass
$vars = array();
$vars['upload_path'] = 'filepath here';
$vars['allowed_types'] = 'zip';
$vars['max_size'] = '30720';
$vars['book_id'] = $book_id;
// add this line
$vars['overwrite'] = true;
// the old file will now get overwritten
$file_name = $this->upload($vars)
A better method is to check the md5 or sha1 checksum of the file.
If two users uploads two different files with the same name to the server, the file on server will be overwritten and it is impossible to distingush the file by just name.
Also, it can be done easily in PHP.
i have an issue with uploading multiple files to disk. here is my code.
i have a request with 2 pictures that gets sent to a upload function. the 2 pictures are in a var called $multiUpload
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$file = array();
$filename = array();
foreach($multiUpload as $key=>$val){
// get the file extension
$file[] = explode('.',$val);
// create custom file name
$filename[] = time().'.'.$file[$key][1];
//send to the upload function
$this->uploadToDisk($folderPath, $filename[$key]);
// sleep 1 sec so that the pic names will be different
sleep(1);
}
return $filename;
}
public function uploadToDisk($folderPath, $filename)
{
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($folderPath);
$adapter->addFilter( 'Rename',array(
'target' => $folderPath."/".$filename,
'overwrite' => true
) );
if ($adapter->receive()) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}
this will return
Array
(
[0] => Array
(
[0] => 1332977938.jpg
[1] => 1332977939.jpg
)
)
but only array[0][0] or 1332977938.jpg will actually get saves to the disk.
Why are they now both get saved? wired
any ideas?
I suspect the second call to uploadToDisk is returning fail because you can only call Zend_File_Transfer_Adapter_Http::receive() once for each file. Since you are not specifying a file when calling receive, it is receiving all of the files the first time you call uploadToDisk and subsequently is failing with a File Upload Attack error.
Here is some code you can try. This tries to receive each file individually and then save them one at a time with each call to uploadToDisk.
A few notes about the code:
The first parameter to uploadToDisk ($val) may need to be changed as I am not sure what the original values are. It should correspond to one of the element names used for the file upload (See Zend_File_Transfer_Adapter_Http::getFileInfo()) for a list of the files.
I changed the method for generating a unique filename so you don't have to sleep(1)
Zend_File_Transfer_Adapter_Abstract::setDestination() is deprecated and will go away in the future. Instead, just use the Rename filter. When using Rename, setDestination() has no effect.
And here it is...
<?php
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$filenames = array();
foreach($multiUpload as $key => $val){
// get the file extension
$ext = explode('.', $val);
$ext = $ext[sizeof($ext) - 1];
// create custom file name
do {
$filename = uniqid(time()) . '.' . $ext;
$diskPath = $folderPath . $filename;
} while (file_exists($diskPath));
$filenames[$key] = $filename;
//send to the upload function
// $val is the file to receive, $diskPath is where it will be moved to
$this->uploadToDisk($val, $diskPath);
}
return $filename;
}
public function uploadToDisk($file, $filename)
{
// create the transfer adapter
// note that setDestination is deprecated, instead use the Rename filter
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->addFilter('Rename', array(
'target' => $filename,
'overwrite' => true
));
// try to receive one file
if ($adapter->receive($file)) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}