How to use readdir in php - Interpretting someone elses code - php

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.

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;

Check if filename exists and

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.

Change an img tag according to Google Calendar schedule

I have a website, where we have a player (click the below link to access it)
FillyRadio Player
There is an image that sits between the background and in front of the waveform canvas.
I need this image to change to different pictures of various presenters, according to a Google Calendar schedule (makes things easier than farting around with code every time we change a schedule).
Is there any way we can make this img src tag change according to a Google Calendar?
Note: I am very very new to working with an API, so a dumbed down answer would be appreciated!
I am not fussy about the method, as long as it works with Chrome and Firefox.
The key to keep the approach as user-friendly as possible (on the image-updating front) without having to rely on time-consuming implementations (i.e., user-friendly interface) is determining the elements which might easily communicate any change to the algorithm. Undoubtedly, these elements are the image files (their names). I have quickly come up with a naming convention delivering what you want (although it is expected to be highly improved by you):
07-23-2013_2.jpg (or .png or any pic extension)
3_1.jpg
All the names include a "_" which separates the first element ("value") from the second one ("duration"). The value can be certain date (mm-dd-yyyy) or a counter: a certain date means that this image has to be used this day, no matter what; the counter is the default behaviour: if there is no pic with the given date, the algorithm will consider the next one by attending to this counter. The duration means the number of days which the given pic is expected to be up.
Just to explain my point properly, I have created a code accounting for the aforementioned naming structure. But, please, understand the intention of this answer properly: this is just to show you an alternative solution and thus I expect you to change/improve this code a lot.
<?php
$goAhead = true;
$today = strtotime(date('Y') . "-" . date('m') . "-" . date('d'));
$lastValue = 0;
//Checking the last stored date and value
if(file_exists ("./config.ini"))
{
$lines = file("./config.ini");
if(count($lines) >= 2)
{
if(strstr($lines[0],'-'))
{
$temp = explode ('-' , $lines[0] );
$goAhead = false;
if(isDateGreaterEqual($temp, $today, false))
{
//The pic has to be changed no matter what
$lastValue = (int)$lines[1];
$goAhead = true;
}
}
}
}
$bestVal = $lastValue;
$bestDuration = 0;
$dirName = './images';
$selectedPic = "";
$bestPic = "";
foreach(glob($dirName . '/*.*') as $file)
{
if(strstr($file,'_') && strstr($file,'.'))
{
$ext = pathinfo($file, PATHINFO_EXTENSION);
$fileNoExtension = basename($file, "." . $ext);
$temp = explode ('_' , $fileNoExtension );
$startVal = $temp[0]; //Date or number
$duration = $temp[1]; //Number of days the given pic will be up
if(strstr($startVal,'-'))
{
$temp = explode ('-' , $startVal );
if(isDateGreaterEqual($temp, $today, true))
{
//If the pic has today's date, the change has to be performed no matter what
updateConfig($duration, $lastValue);
$selectedPic = $file;
break;
}
}
else if($goAhead)
{
//Only in cases where the pic has to be updated
if((int)startVal < $bestVal)
{
$bestVal = (int)startVal;
$bestDuration = $duration;
$bestPic = $file;
}
}
}
}
if($bestPic != "")
{
$selectedPic = $bestPic;
updateConfig($bestDuration, $bestVal);
}
if($selectedPic != "")
{
//$selectedPic -> path of the new image
}
function isDateGreaterEqual($temp, $today, $justEqual)
{
$conditionMet = false;
if(count($temp) == 3)
{
if(checkdate((int)$temp[0], (int)$temp[1], (int)$temp[2]))
{
$stored_date = strtotime($temp[2] . "-" . $temp[0] . "-" . $temp[1]);
if((!$justEqual && $today >= $stored_date) || ($justEqual && $today == $stored_date))
{
//The pic has to be changed no matter what
$conditionMet = true;
}
}
}
return $conditionMet;
}
function updateConfig($duration, $curVal)
{
$finalDate = date('m-d-Y', strtotime("+" . $duration . " days"));
$file = fopen('./config.ini', 'w') or die("can't open file");
fwrite($file, $finalDate . "\r\n");
fwrite($file, $curVal);
fclose($file);
}
?>
This code expects the pictures (with names as described above) to be stored in the folder images. It stores the current configuration (date until which the given picture will be shown and the given counter) in a file called config.ini. The output from this code is $selectedPic which might be blank (no pic change) or include the name of the file of the new picture. This code is expected to be called on a regular basis (just once per day is enough).
The whole point of this proposal is avoiding (usually problematic and unstable) complex calls to external APIs to perform actions which can easily be accomplished internally; that is, a mere proof of concept.

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

Unable to zip more than one file at a time

I wrote a very simple web form that allows my user to view text files from within their Internet browser.
Occasionally, the search criteria entered returns more than one file. So I want to implement a feature whereby the text files returned by the search are compressed into a ZIP.
I got a prototype working but it only compresses the first file. The second or third files are ignored.
Here's my code
<HTML><body><form name="myform" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<fieldset><label for="DBRIDs">RIDs</label><input type="text" id="DBRIDs" name="DBRIDs" >
</fieldset></form></body></HTML>
<?php
function check_search() {
if (isset($_POST['submit'])) {if (!empty($_POST['DBRIDs'])) { $results = getFiles(); }
} else $errors = "Please enter something before you hit SUBMIT.";
return Array($results, $errors);
}
function getFiles() {
$result = null;
$ZIPresult = null;
if (empty($_POST['DBRIDs'])) { return null; }
$mydir = MYDIR;
$dir = opendir($mydir);
$DBRIDs = $_POST['DBRIDs'];
$getfilename = mysql_query("select filename from search_table where rid in (" . $DBRIDs . ")") or die(mysql_error());
while ($row = mysql_fetch_array($getfilename)) {
$filename = $row['filename'];
$result .= '<tr><td>' . $filename . '</td></tr>';
$ZIPresult .= basename($mydir) . '/' . $filename;
}
if ($result) {
$result = "<table><tbody><tr><td>Search Results.</td></tr> $result</table>";
shell_exec("zip -9 SearchResult.zip ". $ZIPresult ." > /dev/null ");
} return $result;
}
The hyperlinks pointing to the file(s) are generated just fine. The ZIP file however only contains the first file listed in the results.
How can I get the ZIP file to capture ALL the files returned??
Thanks for your input.
PS: The new ZipArchive() library/class is not available on our production environment so I chose to use the Unix utility ZIP instead.
There are a number of issues here (security, for one, as it appears that you're not sanitizing your DB inputs), but I'm guess the issue is around the $ZIPresult variable. It doesn't appear (unless I'm missing something) that you have any spaces between your file names, so the shell_exec call is trying to zip "file1.extfile2.extfile3.ext". See what happens if you modify this line:
$ZIPresult .= basename($mydir) . '/' . $filename.' ';

Categories