Check if filename exists and - php

I wondered if there were a way to check if the filename exists and then to add a number after it, I know this - in a basic for is possible so if someone does it once it'll add 1 after it.
But how would you get it to check if someone has done it more than once? So the first time it would add a 1 then a 2 then a 3 and so on?
$title = $_POST['title'];
$content = $_POST['content'];
$compile = $title. "\r\n" .$content;
$content = $compile;
$path = "../data/" .md5($title). ".txt";
$fp = fopen($path,"wb");
fwrite($fp,$content);
fclose($fp);
$con=new mysqli("###","###_public","###","###");
if (!($stmt = $con->prepare("INSERT INTO `blog_posts` (`post_title`,`post_content`,`post_date`) VALUES (?,?,?)")) || !is_object($stmt)) {
die( "Error preparing: (" .$con->errno . ") " . $con->error);
}
$stmt->bind_param('sss', $_POST['title'], $path, $_POST['date']);
if($stmt->execute()) {
echo "Successfully Posted";
} else {
echo "Unsuccessfully Posted";
}
$stmt->close();
Thanks for any help in advance

The general idea would be like this:
$basefilename = "somefile";
$filename = $basefilename;
$i = 0;
while(file_exists("../data/".$filename.".txt") $filename = $basefilename.(++$i);
Adapt as needed.

You can use something like this:
<?php
if(file_exists($filename)) { // check if the file exists in the first place
$i = 1;
while(file_exists($filename.$i)) { // check if the filename with the index exists. If so, increase the $i by 1 and try again
$i++;
}
rename($filename, $filename.$i); // rename the actual file
} else {
// file did not exist in the first place
}

Do not add strings at the end of file name - you would eventually
hit the OS file name length limit pretty soon. You would also fail
to recognize the last added number, when the string gets too big -
you'd have to parse all the numbers from the beginning.
Use glob() to search for a file name.
Parse the file names found for the number at the end and increment
that number.
Use rename() on the file name and check the return status to
avoid racing conditions.
Generally avoid that - use a database or any other system that
supports atomic operations.

Related

Using move_uploaded_file To Rename File BEFORE Being Placed In uploads/ Folder

I've seen questions similar to this but no one seems to have the problem I do.
I've set up a process to check to see if the filename already exists in a MySQL table, and if it does, it puts a timestamp between the filename and the extension (E.G. Test.PDF becomes Test-19:25:36 if it's a duplicate), thus negating any database conflicts.
My issue is that the while the database is updated correctly, the duplicate file isn't uploaded with the timestamp in the name. Instead, it uses the duplicate name and just overwrites the original and creates a ghost "filename" listing in the database.
I've seen you can use move_uploaded_file to rename files in the servers memory before they're uploaded, but I've tried multiple ways and can't get it to rename the file in memory BEFORE attempting to write it to the "/uploads" folder. Here's the upload code:
<?php
include_once 'dbconnect.php';
//check if form is submitted
if (isset($_POST['submit'])) {
// START OF PRE-EXISTING FILE CHECK
$filename = $_FILES['file1']['name'];
$dupeCheck = "SELECT * FROM tbl_files WHERE filename = '$filename'";
if ($output = mysqli_query($con, $dupeCheck)) {
if (mysqli_num_rows($output) > 0) {
$fileArray = pathinfo($filename);
$timeStamp = "-" . date("H:i:s");
$filename = $fileArray['filename'] . $timeStamp . "." . $fileArray['extension'];
}
}
// END OF PRE-EXISTING FILE CHECK
if($filename != '')
{
$trueCheck = true;
if ($trueCheck == true) {
$sql = 'select max(id) as id from tbl_files';
$result = mysqli_query($con, $sql);
//set target directory
$path = 'uploads/';
$created = #date('Y-m-d H-i-s');
$moveTargetVar = "uploads/" . $filename;
move_uploaded_file($_FILES['file1']['tmp_name'], $moveTargetVar);
// insert file details into database
$sql = "INSERT INTO tbl_files(filename, created) VALUES('$filename', '$created')";
mysqli_query($con, $sql);
header("Location: index.php?st=success");
}
else
{
header("Location: index.php?st=error");
}
}
else
header("Location: index.php");
}
?>
Any advice on how to rename a file before it's written to the uploads folder?
I'd suggest not using : to separate your time stamp, because that will cause issue with file name restrictions. Try doing something like:
$timeStamp = "-" . date("H-i-s");
Solved by replacing move_uploaded_file($_FILES['file1']['tmp_name'], $moveTargetVar); with move_uploaded_file($_FILES['file1']['tmp_name'],$path . $filename);
Deprecated $moveTargetVar = "uploads/" . $filename;

PHP Delete file

I am trying to develop a user page for a forum and I'm kinda struggling with the image upload.
The problem is that I would like to limit the user to only be able to upload one single image, but be able to change it anytime. so basically, I would like to either overwrite the existing file either delete the old picture and add a new one instead.
At this point I have a piece of code that adds a timestamp at the end of the file (which I don't really need actually).
CODE:
if(isset($_POST['upload']))
{
$extension=strstr($_FILES['uploadedfile']['name'], ".");
$filename = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name'],
$extension);
$target = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name']);
$valid = true;
if(file_exists($target))
{
$filename = $filename . time();
$target = $filename . $extension;
}
if($valid)
{
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
Make use of unlink() in PHP Manual.
if(file_exists($target))
{
unlink($target); // deletes file
//$filename = $filename . time();
//$target = $filename . $extension;
}
I think this might be a bit better suited for you. You might have to edit it a tad.
if($valid)
{
// Check if user has a file.
$img_check = mysql_query("SELECT * FROM sp_userimage WHERE id = " . (int) $_SESION['user_id']);
if( mysql_num_rows($img_check) > 0 ){
$row = mysql_fetch_object($img_check);
// Delete the file.
unlink($row->path);
}
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
It might be easier to normalize the image type (e.g. only jpegs) and then name the file as the userid. For example:
$target = 'userpics' . DIRECTORY_SEPARATOR . $_SESSION['userid'];
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
This will simply overwrite the old picture with the new one. Given that this type of filename is deterministic, you also don't need to store the filename in the database.
Use unlink() function
read more here PHP unlink
okay ,if u want to delete the file for that particular user only.
then store the filename vs user in some MapTable in db.
mysql_query("CREATE TABLE t_usr_file_map(
usr_id INT NOT NULL ,
file_name VARCHAR(100),
)")
or die(mysql_error());
and at the time of reupload , fetch the filename from the table for that user , unlink it and reupload the fresh one again.
OR,
or u can use PHP file_rename function at the time of upload. rename filename to the userid
rename ( string $oldname , string $newname [, resource $context ] )
and u can always do unlink based on user-id
Its very simple by unlink()
as:
unlink(dirname(__FILE__) . "/../../public_files/" . $filename);
if (file_exists($path))
{
$filename= rand(1,99).$filename;
unlink($oldfile);
}
move_uploaded_file($_FILES['file']['tmp_name'],$filename);

How to use readdir in php - Interpretting someone elses code

For the lack of a better word I'm reverse programming someone else's code in order to replace a portion of it with a more efficient block of code. Up till now I've done primarily basic programming in php so some of the stuff I haven't come across before. Including the following;
$handle = opendir("/directory/of/video/files/"); //not the actual directory
$filename = readdir($handle);
From my understanding readdir() only returns the first file in that directory. However the rest of the php code is set up as if it goes through all the files.
Is there something that I'm misunderstanding?
Update 1 - requested by DCoder
Here's the entire code (except for the bazillion if statements) as requested. The general purpose of the program is to upload video information to a database if the video info is not already there. It would need to look at each file in the directory to check this, but it only looks at one from my understanding.
<html>
<body>
<?php
//opens the directory with symbolic links to the video files (automatically populated)
$handle = opendir("/home/rgood/www/hpa2013fall/");
$filename = readdir($handle);
if ($handle){
while (false !== ($filename = readdir($handle))){
if ($filename[0] == "v" && strlen($filename) == 25)
//retrieves date and time information variables from filename
$month = $filename[7] . $filename[8] . $filename[9];
$day = $filename[10] . $filename[11];
$hour = $filename[13] . $filename[14];
$minute = $filename[16] . $filename[17];
$second = $filename[19] . $filename[20];
/*a bazillion if statements to determine which file its accessed.
This is the part I'm replacing with a database that I've created
and can easily populate using an excel vba script and importing it to mysql*/
if ($month == "February" && $day == "4")
{$title = "Title1"; $description = "Description1";}
elseif //...
//.
//.
//.
else
{$title = "No Title"; $description = "No description.";}
//open database connection
mysql_connect("server","user","password"); //proper connection settings in actual code
//select database
mysql_select_db("Database_Name"); //proper name in code
//this mysql checks to see if the filename already exists in the database
$ifquery = "SELECT * FROM Table WHERE Filename='$filename'";
$ifresults = mysql_query($ifquery);
$rows = array();
//this loop fetches the results. if the same filename is found, it populates $rows[]
while($row = mysql_fetch_array($ifresults))
{
$rows[] = $row;
}
//adds an additional entry into the
if(empty($rows))
{
//this is a readable form of the date/time and a concatenated description
$date = $month . ' ' . $day . ' 2013';
$time = $hour . ':' . $minute . ':' . $second;
//the timedec will be a decimal representation of the date/time
//this is not an easily human-readable format, but it is easily
//used by mysql with the sort function
$timedec = "1" . $monthdec . $day . $hour . $minute . $second;
//sql code to insert the file into the table
$sql = "INSERT INTO Table(Filename,
Title,
Date,
Description,
Time,
timedec)
VALUES ('$filename',
'$title',
'$date', '$description', '$time', '$timedec')";
mysql_query($sql) or die(mysql_error());
}
}
}
closedir($handle);
}
?>
</body>
</html>
Each call to readdir get you another file.
By putting the readdir in a while(), you can read the whole folder.
Use a loop:
$dh = opendir('.');
while($file = readdir($dh)) {
do_something($file);
}
When there's no more files to retrieve, readdir() will return a boolean false, causing the loop to terminate.

Does tmp_name disappear after move_uploaded_file is used?

I have this page where you can send message to multiple people and attach files into it...
Here is my code
<?php
session_start();
$inboxfrom = $_SESSION['loginusername'];
$inboxto = $_POST['inboxto'];
$inboxsubject = $_POST['inboxsubject'];
$inboxcontent = $_POST['inboxcontent'];
$inboxtime = date('g:i A', time()+(6*60*60));
$inboxdate = date('Y-m-d', time()+(6*60*60));
mysql_connect("127.0.0.1", "root", "")or die("Cannot Connect toDb");
mysql_select_db("Abbot_db");
$count = 0;
function generateRandomString($length = 8){
$string = "";
$possible = "0123456789bcdfghjkmnpqrstvwxyz"; //character that can be used
for($i=0;$i < $length;$i++){
$char = substr($possible, rand(0, strlen($possible)-1), 1);
if (!strstr($string, $char)){
$string .= $char;
}
}
return $string;
}
if (count($inboxto) != 0){
$count = 0;
while ($count < count($inboxto)){
$recepient = $_POST['inboxto'][$count];
mysql_query("INSERT INTO Inbox_tbl(InboxTo, InboxFrom, InboxSubject, InboxContent, InboxTime, InboxDate,InboxStatus,ToDelete,FromDelete)VALUES ('$recepient','$inboxfrom','$inboxsubject','$inboxcontent','$inboxtime','$inboxdate','Unread','No','No')");
$recepient_result = mysql_query("SELECT * FROM Accounts_tbl WHERE UserID='$recepient'");
if (mysql_result($recepient_result, 0, "UserTypeID") == 1){
$notiurl = "LMSadmin_inbox.php";
} else if (mysql_result($recepient_result, 0, "UserTypeID") == 2) {
$notiurl = "LMSteacher_inbox.php";
} else {
$notiurl = "LMSstud_inbox.php";
}
mysql_query("INSERT INTO Noti_tbl(NotiTo,NotiFrom,NotiContent,NotiDate,NotiTime,NotiType,NotiUrl)
VALUES('$recepient','$inboxfrom','has sent you a message','$inboxdate','$inboxtime','Message','$notiurl')");
//---------------------------------------------------------
$countto = 0;
$cont = generateRandomString(128);
$folder = "./Attachments/".$cont;
$name = $_FILES['file']['name'];
if (!empty($name)){
while (is_dir($folder)){
$cont = generateRandomString(128);
$folder = "./Attachments/".$cont;
}
mkdir($folder, 0700, true);
}
while ($countto < count($_FILES['file']['name'])){
$name = $_FILES['file']['name'][$countto];
$type = $_FILES['file']['type'][$countto];
$tmp_name = $_FILES['file']['tmp_name'][$countto];
$folder = "Attachments/".$cont."/";
move_uploaded_file($tmp_name, $folder.$name);
$fileurl = $cont."/".$name;
$dummypost = mysql_query("SELECT * FROM Inbox_tbl ORDER BY InboxID DESC");
$msgid = mysql_result($dummypost, 0, "InboxID");
mysql_query("INSERT INTO Attachments_tbl(FileUrl,FileName,AttachType,AttachID)
VALUES('$fileurl','$name','Message',$msgid)");
$countto++;
}
//----------------------------------------------
$count++;
}
}
header('Location: ' . $_SERVER['HTTP_REFERER']);
?>
now the result after I put multiple recepients and multiples is that... The first recepient will get the attachments.. meaning the folder of attachment will be randomy generated and the files would be put in there.... but on the next recepient the attachments would not be moved on their respective folder.. I can see the folder have been made but the files arent moved..
MY question is.. does the "temp_name" disappear after you use the "move_uploaded_file" code? Because I think thats is the reason the files arent not move.. Is so can you suggest any alternate code i can use?
move_uploaded_file() relocates the file to the set target location with rendering the tmp_name useless afterwards.
What you should do is to create a "puffer" folder where you originally move the uploaded file, and then call copy() as many times as you need to deliver the file to the recipient folders. When the file is put to every needed location, you can unlink() the file from this puffer folder.
Alternatively, you might put the file to only one location (to eliminate redundancy and overuse of storage space), and make links in your Attachments_tbl to this same file in a set attachments folder. However, this needs remodelling of how your system works to make sure that the (now one and only) attachment file is only removed after every record pointing to it is removed also.
Yes, the file is moved, this is why you can't find it. I suggest that you:
Move the inner while loop (the one for the uploaded files) before the first while loop (for the recipients), and move the uploaded files to a location that you specify
Create a new inner while loop that copies the files from the location you specified earlier to each user's attachments folder

line count path problem

$f="../mts/sites/default/files/test.doc";//in this way i am able to find line count,but i am not getting how i can give folder path for line counting..if i give path as $safe_filename and $target_path.$safe_filename it's coming file content not opening. Please check the code and help me out thanks in advance
<?php
$nid = 1;
$teaser = false;
// Load node
$node = node_load(array('nid' => $nid));
// Prepare its output
if (node_hook($node, 'view')) {
node_invoke($node, 'view', $teaser, false);
}
else {
$node = node_prepare($node, $teaser);
}
// Allow modules to change content before viewing.
node_invoke_nodeapi($node, 'view', $teaser, false);
// Print
print $teaser ? $node->teaser : $node->body;
$target_path = "../mts/sites/default/files/ourfiles/";
//$myfile = basename( $_FILES['uploadedfile']['name']);
$safe_filename = preg_replace(
array("/\s+/", "/[^-\.\w]+/"),
array("_", ""),
trim($_FILES['uploadedfile']['name']));
$target_path = $target_path.$safe_filename;
if(file_exists($target_path))
{
echo "<script language=\"javascript\">";
echo "window.alert ('File already exist');";
echo "//--></script>";
}
elseif(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "<script language=\"javascript\">";
echo "window.alert ('File uploaded succesfully');";
echo "//--></script>";
/*
echo "The file ". basename( $_FILES['uploadedfile']['name']).
" has been uploaded";
*/
}
$con = mysql_connect("localhost","mts","mts");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
// Create table
mysql_select_db("mts", $con);
$f="../mts/sites/default/files/test.doc";//in this way i am able to find line count,but i am not getting how i can give folder path for line counting
// count words
$numWords = str_word_count($str)/11;
echo "This file have ". $numWords . " words";
echo "This file have ". $numWords . " lines";
mysql_query("INSERT INTO mt_upload (FileName,linecount, FilePath,DateTime)
VALUES ('".$safe_filename."','".$numWords."', '".$target_path.$safe_filename."',NOW())");
// Execute query
mysql_query($sql,$con);
mysql_close($con);
?>
emphasized text
This is not a very safe way of doing things. If two users submitted files with the same filename, they would overwrite each other. This limits the user to a unique filename, which after a while of running a system becomes a problem. Not to mention that the user would be quite puzzled if he ever got such a message.
A much better solution is to generate your own filename for every file. You could make a long random string, or maybe take the mysql_insert_id() for the inserted record in mt_upload table. Then you would also not need to mess around with regexps, and the whole thing would be much simpler. In the mt_upload table you can keep the old filename if you want to show it to the user or something.
If that's the exact code, then the problem is that you call str_word_count() on $str but don't appear to set $str anywhere.
Function to count lines in all the files residing in a certain directory
function linecount_dir($dir) {
$ig = array('.','..');
$d = dir($dir);
while (false !== ($entry = $d->read())) {
if (!in_array($entry,$ig)) {
$total += linecount($d->path . "/$entry");
}
}
$d->close();
return $total;
}
Function to count lines
define(BLOCK_SIZE,131072);
function linecount($filename) {
$f = fopen($filename,'r');
while (!feof($f)) {
$d = fread($f,BLOCK_SIZE);
$rcount += substr_count($d, "\n");
$ncount += substr_count($d, "\r");
}
fclose($f);
return (($rcount >= $ncount) ? $rcount : $ncount);
}
Applied to your code
$f="../mts/sites/default/files/test.doc";//in this way i am able to find line count,but i am not getting how i can give folder path for line counting
// count words
$numWords = str_word_count($str)/11;
// count lines
$numLines = linecount($f);
echo "This file have ". $numWords . " words";
echo "This file have ". $numLines . " lines";
$f="../mts/sites/default/files/".$safe_filename;

Categories