I am using the edsdk/flmngr library for a personal php/laravel project. However, I want to add the following constraint:
When a user is uploading a file into the gallery from the CMS, the file name should be cleared of all symbols and weird characters as well as empty spaces. By default I know that it removes some of the symbols, but it definetely does not remove spaces.
e.g. Top Three Countries To Study.jpg
should be renamed to TopThreeCountriesToStudy.jpg but it does not.
Any hints on which files to change or how to accomplish this is much appreciated.
I tried editing the fixFileName method in the Utils.php class so that the name that end up being used has no spaces, but for some reason it does not seem to work.
public static function fixFileName($name) {
$newName = '';
for ($i = 0; $i < strlen($name); $i++) {
$ch = substr($name, $i, 1);
if (strpos(Utils::PROHIBITED_SYMBOLS, $ch) !== FALSE) {
$ch = '_';
}
$newName = $newName . $ch;
$newName = Str::replace(" ", "", $newName); //THIS IS THE LINE I ADDED
}
return $newName;
}
Related
I am building an application where users can create folders and upload files. Of course, I need to validate the POST-Values so that a user cannot delete/overwrite files they aren't allowed to. What I am doing at the moment: When a file gets uploaded, I add a suffix to the file name, so "image.jpg" becomes "image.jpg-foo". The file paths are checked for "../" and "..\".
My question is: is this method secure enough, or is a user still able to get to another dir with another command? I don't want to change the file names to random characters as I don't wanna use a Database (the script has to be as small as possible).
My functions for the file path look like this (I user BetterFoldername for all user inputs) :
function endswith($string, $test) {
$strlen = strlen($string);
$testlen = strlen($test);
if ($testlen > $strlen)
return false;
return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
}
function BetterFoldername($name) {
$name = str_replace("../","",$name);
$name = str_replace("..\\","",$name);
$name = str_replace("//","/",$name);
$name = str_replace("\\\\","\\",$name);
if(endswith($name, "/") || endswith($name, "\\")) {
$name = substr($name, 0, -1);
}
if (preg_match("/[^\sA-Za-z0-9_.\/\-]/", $name)) {
exit("An error occured!");
}
return $name;
}
This question already has answers here:
How to generate a random, unique, alphanumeric string?
(31 answers)
Closed 9 years ago.
How would I go about creating a random string of text for use with file names?
I am uploading photos and renaming them upon completion. All photos are going to be stored in one directory so their filenames need to be unique.
Is there a standard way of doing this?
Is there a way to check if the filename already exists before trying to overwrite?
This is for a single user environment (myself) to show my personal photos on my website however I would like to automate it a little. I don't need to worry about two users trying to upload and generating the same filename at the same time but I do want to check if it exists already.
I know how to upload the file, and I know how to generate random strings, but I want to know if there is a standard way of doing it.
The proper way to do this is to use PHP's tempnam() function. It creates a file in the specified directory with a guaranteed unique name, so you don't have to worry about randomness or overwriting an existing file:
$filename = tempnam('/path/to/storage/directory', '');
unlink($filename);
move_uploaded_file($_FILES['file']['tmp_name'], $filename);
function random_string($length) {
$key = '';
$keys = array_merge(range(0, 9), range('a', 'z'));
for ($i = 0; $i < $length; $i++) {
$key .= $keys[array_rand($keys)];
}
return $key;
}
echo random_string(50);
Example output:
zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8
EDIT
Make this unique in a directory, changes to function here:
function random_filename($length, $directory = '', $extension = '')
{
// default to this files directory if empty...
$dir = !empty($directory) && is_dir($directory) ? $directory : dirname(__FILE__);
do {
$key = '';
$keys = array_merge(range(0, 9), range('a', 'z'));
for ($i = 0; $i < $length; $i++) {
$key .= $keys[array_rand($keys)];
}
} while (file_exists($dir . '/' . $key . (!empty($extension) ? '.' . $extension : '')));
return $key . (!empty($extension) ? '.' . $extension : '');
}
// Checks in the directory of where this file is located.
echo random_filename(50);
// Checks in a user-supplied directory...
echo random_filename(50, '/ServerRoot/mysite/myfiles');
// Checks in current directory of php file, with zip extension...
echo random_filename(50, '', 'zip');
Hope this is what you are looking for:-
<?php
function generateFileName()
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789_";
$name = "";
for($i=0; $i<12; $i++)
$name.= $chars[rand(0,strlen($chars))];
return $name;
}
//get a random name of the file here
$fileName = generateName();
//what we need to do is scan the directory for existence of the current filename
$files = scandir(dirname(__FILE__).'/images');//assumed images are stored in images directory of the current directory
$temp = $fileName.'.'.$_FILES['assumed']['type'];//add extension to randomly generated image name
for($i = 0; $i<count($files); $i++)
if($temp==$files[$i] && !is_dir($files[$i]))
{
$fileName .= "_1.".$_FILES['assumed']['type'];
break;
}
unset($temp);
unset($files);
//now you can upload an image in the directory with a random unique file name as you required
move_uploaded_file($_FILES['assumed']['tmp_name'],"images/".$fileName);
unset($fileName);
?>
I need to give incresing number to files as the upload. I am usinf SFWUpload. I have this code:
mkdir("../../imagenes/".$codigo , 0777);
$i = 1;
$nombre = $codigo.'_'.$i.'.jpg';
move_uploaded_file($_FILES['Filedata']['tmp_name'], "../../imagenes/".$codigo."/".$nombre);
chmod("../../imagenes/".$codigo."/".$_FILES['Filedata']['name'], 0777);
The $codigo is the code, for example 101213, so i need the pictures to upload like 101213_1.jpg, 101213_2.jpg, 101213_3.jpg, and so on.
The problem is that SWFUpload runs the php ONCE per picture, so i can not use a foreach loop (I guess).
I need the script to check if the file exists and write the next. For example, if 101213_4.jpg exists, then write 101213_5.jpg.
Can you help me how can I do this.?? I am novice at php, and tried everything.! :(
Thanks in advance
Roberto
Here's a function I use:
function cleanup_name($name){ //accepts name and cleans it up.
$finalDir='/home/username/uploads';
# Go to all lower case for consistency
$name = strtolower($name);
//echo("Name is $name<br>");
$matches=split('\.',$name);
foreach ($matches as $key=>$value){
$exkey=$key;
$exvalue=$value; //if there is more than one period, this will find the actual extension.
//echo("Key $key|$exkey Value $value|$exvalue<br>");
}
if ($exkey<1){die('The file must have an extension.');}
$extension=".".$exvalue;
$loop=0;
while ($loop<($exkey)){
if ($loop<($exkey-1)){$matches[$loop]=".".$matches[$loop];} // this puts extra periods back into the string, but the borrowed code will replace them with underscores.
$stem.=$matches[$loop];
$loop++;
}
//echo("Stem is $stem<br>");
//echo("Extension is $extension<br>");
# Convert whitespace of any kind to single underscores
$stem = preg_replace('/\s+/', '_', $stem);
# Remove any remaining characters other than A-Z, a-z, 0-9 and _
$stem = preg_replace('/[^\w]/', '', $stem);
# Make sure the file extension has no odd characters
if (($extension != '') &&
(!preg_match('/^\.\w+$/', $extension)))
{
echo("odd characters in extension");
//die("Bad file extension");
return FALSE;
}
$safeExtensions = array(
'.zip',
'.psd',
'.pdf',
'.jpg',
'.jpeg',
'.gif',
'.rar',
'.gz',
'.ai',
'.eps',
'.bmp',
'.pub',
'.xls',
'.doc',
'.wpd',
'.rtf',
'.tiff',
'.tif',
'.pcx',
'.ttf',
'.png',
'.txt',
'.mp3',
'.avi',
'.mov',
'.wav'
);
if (!in_array($extension, $safeExtensions)) {
echo("Extension "$extension" not approved.");
//die("File extension not approved");
return FALSE;
}
# Search for a unique filename by adding a number to the
# stem (first we try without, of course)
$suffix = '';
while (file_exists($finalDir."/".$stem.$suffix.$extension)) {
if ($suffix == '') {
$suffix = '0';
} else {
$suffix++;
}
}
# Put the full name back together
$name = "$stem$suffix$extension";
return $name;
}
Pay special attention to the section with this: " while (file_exists..."
Well... you can try to get the current number of files on the folder and get $i from there:
mkdir("../../imagenes/".$codigo , 0777);
$i = count(glob("../../imagenes/".$codigo.'_*.jpg')) + 1;
$nombre = $codigo.'_'.$i.'.jpg';
move_uploaded_file($_FILES['Filedata']['tmp_name'], "../../imagenes/".$codigo."/".$nombre);
chmod("../../imagenes/".$codigo."/".$nombre, 0777);
Try that code...
How do I create a temporary file with a specified extension in php.
I came across tempnam() but using it the extension can't be specified.
Easiest way i have found is to create tempfile and then just rename it. For example:
$tmpfname = tempnam(sys_get_temp_dir(), "Pre_");
rename($tmpfname, $tmpfname .= '.pdf');
my way is using tempnam
$file = tempnam(sys_get_temp_dir(), 'prefix');
file_put_contents($file.'.extension', $data);
{
//use your file
}
unlink($file);//to delete an empty file that tempnam creates
unlink($file.'.extension');//to delete your file
This might simulate mkstemp() (see http://linux.die.net/man/3/mkstemp) a bit, achieving what you want to do:
function mkstemp( $template ) {
$attempts = 238328; // 62 x 62 x 62
$letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$length = strlen($letters) - 1;
if( mb_strlen($template) < 6 || !strstr($template, 'XXXXXX') )
return FALSE;
for( $count = 0; $count < $attempts; ++$count) {
$random = "";
for($p = 0; $p < 6; $p++) {
$random .= $letters[mt_rand(0, $length)];
}
$randomFile = str_replace("XXXXXX", $random, $template);
if( !($fd = #fopen($randomFile, "x+")) )
continue;
return $fd;
}
return FALSE;
}
So you could do:
if( ($f = mkstemp("test-XXXXXX.txt")) ) {
fwrite($f, "test\n");
fclose($f);
}
Let's say tempnam() gives you a file of "filename". You move it to "filename.ext". At any point, tempnam() can give you "filename" again. If you check for "filename.ext", reject the filename given by tempnam(), and call it again, you still end up with the possibility that between one step and another, a file will get created with the same name. (This is discussed in the user comments on the documentation page for tempnam(): https://www.php.net/manual/en/function.tempnam.php.)
However, if you just leave the file created by tempnam() alone (not deleting "filename" until you delete "filename.ext") and work with that filename + the extension, then there is no chance that tempnam() will use that filename again (as far as I can see). Yes, it is messy to have "filename" and "filename.ext" for every single file. On the other hand, it solves the problem.
public static function makeTempFileInFolder($prefix, $suffix, $folder="")
{
if (strlen($folder)==0) $folder = sys_get_temp_dir();
do {
$file = $folder."/".$prefix.rand(1,99999).time().$suffix;
} while (file_exists($file));
return $file;
}
The same as tempnam() except the additional parameter:
function tempnamp($dir, $prefix, $postfix) {
$maxAttempts = 1000;
// Trim trailing slashes from $dir.
$dir = rtrim($dir, DIRECTORY_SEPARATOR);
// If we don't have permission to create a directory, fail, otherwise we will
// be stuck in an endless loop.
if (!is_dir($dir) || !is_writable($dir)) return false;
// Make sure characters in prefix and postfix are safe.
if (strpbrk($prefix, '\\/:*?"<>|') !== false) return false;
if (strpbrk($postfix, '\\/:*?"<>|') !== false) return false;
// Attempt to create a random file until it works.
$attempts = 0;
do
{
$path = $dir.DIRECTORY_SEPARATOR.$prefix.mt_rand(100000, mt_getrandmax()).$postfix;
$fp = #fopen($path, 'x+');
} while (!$fp && $attempts++ < $maxAttempts);
if ($fp) fclose($fp);
return $path;
}
That 'p' at the end of the name stands for 'postfix'.
I prefer this solution:
$uid = uniqid('', true);
$path = sys_get_temp_dir() . "some_prefix_$uid.myextension";
Note: I do not put the prefix in uniqid because, IMHO, it's not its duty
Maybe using
move_uploaded_file($tmp_name, "$uploads_dir/$name.myextension");
See http://php.net/manual/en/function.move-uploaded-file.php#example-2209
Rename does it, find the extension with pathinfo and then replace with the extension you want.
$tmpfname = tempnam(sys_get_temp_dir(), 'FOO');
$newname = str_replace(pathinfo($tmpfname, PATHINFO_EXTENSION),'pdf',$tmpfname);
rename($tmpfname, $newname);
//do what you want with $newname
unlink($newname);
So I am creating trying to create a PHP script where the client can create a folder with a 10 digit name of random letters and numbers, and than save the document they are currently working on into that folder. Its like a JSfiddle where you can save what you are currently working on and it makes a random folder. My issue is that it wont create my directory, and the idea is correct, and it should work. However, PHP isn't saving an Error Log so I cannot identify the issue. Here's what I got so far.
PHP
save_functions.php
<?php
function genRandomString() {
$length = 10;
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
$string = '';
for ($p = 0; $p < $length; $p++) {
$string .= $characters[mt_rand(0, strlen($characters))];
}
return $string;
}
<?php
function createFolder() {
$folderName = genRandomString(); //Make a random name for the folder
$goTo = '../$folderName';//Path to folder
while(is_dir($goTo)==true){ //Check if a folder with that name exists
$folderName = genRandomString();
$goTo = '../$folderName';
}
mkdir($goTo,7777); //Make a directory with that name at $goTo
return $goTo; //Return the path to the folder
}
?>
create_files.php
<?php
include('save_functions.php');//Include those functions
$doc = $_POST['doc'];//Get contents of the file
$folder = createFolder();//Make the folder with that random name
$docName = '$folder/style.css';//Create the css file
$dh = fopen($docName, 'w+') or die("can't open file");//Open or create the file
fwrite($dh, $doc);//Overwrite contents of the file
fclose($dh);//Close handler
?>
The call to mkdir($goTo,7777) has wrong mode, this is usually octal and not decimal or hex. 7777 is 017141 in octal and thus tries to set non-existent bits. Try the usual 0777.
But why don't you just use tempnam() or tmpfile() in your case?