First off, I am totally new to PHP, but so far i love the possibilities i have seen with it.
Ok, heres my problem. I have a script that will automatically scan a folder and show me the file names of that folder in a drop-down menu.
<?php
$dirname = "logs";
$dir = opendir($dirname);
echo '<select name="file2">';
echo '<option value="">Logfiles</option>';
while(false != ($file = readdir($dir)))
{
if(($file != ".") and ($file != ".."))
{
echo "<option value=".$file.">$file</option>";
}
}
echo '</select>';
?>
So far so good, that part works just fine.
I then have a piece of code that would show me the contents of a chosen file.
<?php
$content = file("filenamehere");
$data = implode("<br>",$content);
echo $data;
?>
This part on its own also works fine.
I now want to combine these 2 scripts. This is where i get totally lost. I have tried all various combinations of which variable to put as a "filenamehere", but I only get as far as having my choice from the drop-down echoing the chosen filename in the drop-down button. I have not been able to actually get the 2nd part of the code to display the file contents of the file I have chosen. I tried things like ("$file") for the $content variable but nothing happens.
Of course any other single script solution would also be great. I just need to be able to scan a folder, have its files listed in a drop-down, and once i choose a file i want it to be displayed on the page.
Any help would be deeply appreciated since im a total beginner in PHP.
Cheers.
Am assuming you are doing everything in a single page. I have wrapped a form tag around the select dropdown and added a submit button
echo '<form name="displayfile" action="" method="POST">';
echo '<select name="file2">';
echo '<option value="">Logfiles</option>';
while(false != ($file = readdir($dir)))
{
if(($file != ".") and ($file != ".."))
{
echo "<option value=".$file.">$file</option>";
}
}
echo '</select>';
echo '<input type="submit" value="display file" />';
echo '</form>';
The second part
<?php
//file2 is the name of the dropdown
$selectedfile = #$_POST['file2'];
$content = file($selectedfile);
$data = implode("<br>",$content);
echo $data;
?>
Hope this helps
Related
My folder structure has 4 layers with my form in the top layer, currently it displays the files in the top layer only, I want to be able to select a subfolder and display the files in it so they can be deleted if necessary.
Produce
Produce/Meat
Produce/Meat/Beef
Produce/Meat/Beef/Portions
Produce/Meat/Beef/Packaged
Produce/Vegtables
Produce/Vegetables/Fresh
Produce/Vegetables/Fresh/Local etc,.
My form displays the contents of the folder it is in with checkboxes, I can then tick boxes and delete files, but I have added a select and want to be able to display the contents of the selected subfolder and delete files. I made two submit buttons and both work, but the delete feature only works if it's in the top folder.
if ($_POST['delete'] == 'Submit')
{
foreach ((array) $_POST['select'] as $file) {
if(file_exists($file)) {
unlink($file);
}
elseif(is_dir($file)) {
rmdir($file);
}
}
}
$files = array();
$dir = opendir('.');
while(false != ($file = readdir($dir))) {
if(($file != ".") and ($file != "..")and ($file != "error_log")) {
$files[] = $file;
}
}
if ($_POST['action'] == 'Change') {
if($_POST['folder'] == 'AAA'){
$files = array();
$dir = opendir('/home/mysite/public_html/Produce/Vegetables/');
while(false != ($file = readdir($dir))) {
if(($file != ".") and ($file != "..")) {
$files[] = $file;
}
}
}
if($_POST['folder'] == 'BBB'){
$files = array();
$dir = opendir('/home/mysite/public_html/Produce/Meat');
while(false != ($file = readdir($dir))) {
if(($file != ".") and ($file != "..")) {
$files[] = $file;
}
}
}
}
natcasesort($files);
?>
<form id="delete" action="" method="POST">
<?php
echo '<table><tr>';
for($i=0; $i<count($files); $i++) {
if ($i%5 == 0) {
echo '</tr>';
echo '<tr>';
}
echo '<td style="width:180px">
<div class="select-all-col"><input name="select[]" type="checkbox" class="select" value="'.$files[$i].'"/>
'.$files[$i].'</div>
<br />
</td>';
}
echo '</table>';
?>
</table>
<br>
Choose a folder:
<select name="folder"><option value="this" selected>This folder</option><option value="BBB">Meat</option><option value="CCC">Meat/Beef</option><option value="DDD">Meat/Beef/Portions</option><option value="EEE">Meat/Beef/Packaged</option><option value="FFF">Vegetables</option><option value="GGG">Vegetables/Fresh</option><option value="HHH">Vegetables/Fresh/Local</option><option value="III">Vegetables/Fresh/Packaged</option></select>
<br>
<input class="button" type="submit" form="delete" name="action" value="Change"><br>
<button type="submit" form="delete" value="Submit">Delete File/s</button>
</form><br>
How can I utilise the selected value to accomplish this?
First, I'd like to address why you are unable to delete files outside of the top folder. You never change the "current working directory" so calling the deleting functions on deep files will never work as intended and could delete the files in the top folder. To correct this, you will either need to include the path with each file/directory to be deleted or call chdir() once so that unlink() and rmdir() are looking in the right place.
I believe your project still has some natural maturing to do including security and UX. I'll provide a generalized/simple snippet for you to consider/compare against your project to hopefully give you a bit more traction in your development.
Your users will be able to make one of two choices on submission: Change Directory & Remove Files/Directories
For the directory change, your program will need to submit two necessary pieces of information:
The action (action="change")
The new folder (newfolder={variable})
For the file/directory deletion, there will be three necessary pieces of information:
The action (action="delete")
The files/directory (files[]={variable})
The directory to access (folder={variable}) * the value in the <select> cannot be trusted, because a user could change the selected value before selecting files in the current directory for deletion. This value must be statically preserved.*Note, you could just add the paths to the filenames in the checkbox values and eliminate the hidden input -- this will be a matter of programming preference.
Purely for demonstration purposes, I'll reference this static array of folders in my code:
$valid_folders=[
'Produce',
'Produce/Meat',
'Produce/Meat/Beef',
'Produce/Meat/Beef/Portions',
'Produce/Meat/Beef/Packaged',
'Produce/Vegetables',
'Produce/Vegetables/Fresh',
'Produce/Vegetables/Fresh/Local',
'Produce/Vegetables/Fresh/Packaged'
];
In reality, you'll probably want to generate an array of valid/permitted/existing folders. I might recommend that you have a look at this link: List all the files and folders in a Directory with PHP recursive function
if(isset($_POST['action'])){ // if there is a submission
if($_POST['action']=="Delete"){ // if delete clicked
if(in_array($_POST['folder'],$valid_folders)){
$folder=$_POST['folder']; // use valid directory
}else{
$folder=$valid_folders[0]; // set a default directory
}
chdir($folder); // set current working directory
//echo "<div>",getcwd(),"</div>"; // confirm directory is correct
foreach($_POST['files'] as $file){ // loop through all files submitted
if(is_dir($file)){ // check if a directory
rmdir($file); // delete it
}else{ // or a file
unlink($file); // delete it
}
}
}elseif($_POST['action']=="Change"){ // if change clicked
if(in_array($_POST['newfolder'],$valid_folders)){ // use valid new directory
$folder=$_POST['newfolder'];
}else{
//echo "Sorry, invalid folder submitted";
$folder=$valid_folders[0]; // set a default directory
}
}
}else{
$folder=$valid_folders[0]; // no submission, set a default directory
}
$dir = opendir("/{$folder}"); // set this to whatever you need it to be -- considering parent directories
//echo "Accessing: /$folder<br>";
while(false!=($file=readdir($dir))){
if(!in_array($file,['.','..','error_log'])){ // deny dots and error_log; you should also consider preventing the deletion of THIS file as well! Alternatively, you could skip this iterated condition and filter the $files array after the loop is finished.
$files[] = $file;
}
}
natcasesort($files);
echo "<form action=\"\" method=\"POST\">";
echo "<select name=\"newfolder\">";
//echo "<option value=\"\">Select a folder</option>"; // this isn't necessary if the neighboring button is descriptive
foreach($valid_folders as $f){
echo "<option",($folder==$f?" selected":""),">{$f}</option>"; // if a previously submitted directory, show it as selected
}
echo "</select> ";
echo "<button name=\"action\" value=\"Change\">Change To Selected Folder</button>";
echo "<br><br>";
echo "Delete one or more files:";
echo "<table><tr>";
for($i=0,$count=sizeof($files); $i<$count; ++$i){
if($i!=0 && $i%5==0){ // see the reason for this change # https://stackoverflow.com/questions/43565075/new-containing-div-after-every-3-records/43566227#43566227
echo "</tr><tr>";
}
echo "<td style=\"width:180px;\">";
echo "<div><input name=\"files[]\" type=\"checkbox\" value=\"{$files[$i]}\">{$files[$i]}</div>";
echo "</td>";
}
echo "</tr></table>";
echo "<input type=\"hidden\" name=\"folder\" value=\"{$folder}\">"; // retain current directory
echo "<button name=\"action\" value=\"Delete\">Delete Checked File(s)</button>";
echo "</form>";
As for form structure, you could implement <input type="submit"> or <button> to submit the form. I won't discuss the caveats for this question.
You see, in the form, $folder is a value that invisibly passed with the submission. This stops the user from moving to an unintended directory when deleting files.
When action=Delete then $folder and $files are used for processing.When action=Change only newfolder is used for processing.
When there is no action a default folder is declared and files will be listed.
<textarea placeholder="Source code of file" class="source">
<?php echo ($thesource) ?>
</textarea>
<?php
$blacklist = array("one.jps", "two.txt", "four.html");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
$thesource = file_get_contents($entry);
echo "<div class='post'
<p>$entry</p>
</div>
";
}
}
closedir($handle);
}
?>
Output:
<textarea placeholder="Source code of file" class="source">
<!DOCTYPE html>
<html>
etc
etc
</body>
</html>
</textarea>
<p>ok.html</p>
<p>source.php</p>
<p>sub.html</p>
<p>stylesheet.css</p>
As confusing this may look, let me try to explain what I want to achieve.
Lets say that there are some files in a directory (4 in this case). The PHP code I am using will echo out all those 4 files onto the page that the PHP code is on - it excludes everything in the blacklist. So it will look a little something like this:
<p>ok.html</p>
<p>source.php</p>
<p>sub.html</p>
<p>stylesheet.css</p>
There is also a textarea:
<textarea placeholder="Source code of file" class="source">
<?php echo ($thesource) ?>
</textarea>
This textarea will have a value of $thesource. Whatever is in the $thesource variable will appear in the textarea.
To define the $thesource variable, this is the PHP code I am using:
$thesource = file_get_contents($entry);
Note that $entry is all the files that are echoed out onto the page (as explained above - 4 files in this case)
I am trying to make it so that, whenever a user clicks on one of the files:
<p>ok.html</p>
<p>source.php</p>
<p>sub.html</p>
<p>stylesheet.css</p>
When the user clicks on those listed above, it will display the source code of the clicked file in the textarea.
The current source code I am using, only echo's out the source code of the current file containing the PHP code.
How would I achieve this? Thanks - and if you are still unsure of what I am trying to achieve, then please ask!
This should work for you:
First i get all files in a directory with glob() which aren't in the blacklist. After that i print a list which you can click on it.
If you click on it the file get's included and displayed in the textarea.
<?php
$blacklist = array("one.jps", "two.txt", "four.html");
$files = array_diff(glob("*.*"), $blacklist);
foreach($files as $file)
echo "<div class='post'><a href='" . $_SERVER['PHP_SELF'] . "?file=" . $file . "'><p>" . $file . "</p></a></div>";
if(!empty($_GET["file"]) && !in_array($_GET["file"], $blacklist) && file_exists($_GET["file"]))
$thesource = htmlentities(file_get_contents($_GET["file"]));
?>
<textarea rows="40" cols="100" placeholder="Source code of file" class="source"><?php if(!empty($thesource))echo $thesource; ?></textarea>
I am using this code to list all the files in a Dir:
<?php
if ($handle = opendir('CD300/')) {
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != ".."){
$thelist .= '<a href="/CD300/'.$file.'" target="_blank"
style="color: #0f33cc">'.$file.'</a></br>';
}
}
closedir($handle);
}
echo "
<div id='output'>
List of help files:</div>
<div id='List'>
<?=$thelist
</div>"
?>
If I set the a href to have < li> tags then I get the list however the first result is not indented and the rest are. As I currently have it set, all of the files are displayed correctly however the first link is non clickable.
Am I missing something?
Remove the <?= markup, you are already printing the output from within PHP, so what happens is that <?= is literally appended in the first line just before you output the file list.
I have written this simple script display all the files in a directory as a set of buttons.
This code reads from the upload directory and displays all files inside a submit button in a form.
$handle = opendir("upload");
echo '<form name="form" method="post" action="download.php">';
while($name = readdir($handle)) {
echo '<input type="submit" name="file" value='.$name.' />';
}
echo '</form>';
Now the issue here is; every time I run the script I find two button at the beginning with contents . and ..
I have not been able to figure out what causes this issue.
What you have encountered are two special files used by the file system.
. represents the current directory you are in.1
.. represents the parent directory of the current directory.2
Footnotes:
1. A path such as "/my_dir/././././././file" is equivalent to "/my_dir/file".
2. A path such as "/my_dir/../my_dir/../my_dir/file" is equivalent to "/my_dir/file" since .. will make you move "up" one level.
To get around the issue of showing these two to your user filter the content returned by readdir using something as the below:
while ($name = readdir ($handle)) {
if ($name == '.' || $name == '..')
continue; /* don't echo anything, skip to next read */
echo '<input type="submit" name="file" value='.$name.' />';
}
the directory listing includes . for the current dir and .. for the parent dir.
I usually use this that i got from the PHP manual (http://php.net/manual/en/function.readdir.php)
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "$entry\n";
}
}
closedir($handle);
}
so what you need to do is to exclude the . and .. from the output.
Another solution is to use a FilesystemIterator like this:
foreach(new FilesystemIterator('upload') as $file){
echo $file;
}
It will automatically skip . and .. entries in the filesystem.
I have the following PHP code to display the file structure of my site. This gives my a very nice indented structure with folder and file images.
How can I add JQuery to this so I can collapse and expand the folders? I tried a couple of jquery plugins but they didn't work.
Can you suggest a jquery plugin or an article or code snippet?
Thank you!
<?php
$path = ROOT_PATH;
$dir_handle = #opendir($path) or die("Unable to open $path");
list_dir($dir_handle,$path);
function list_dir($dir_handle,$path)
{
echo "<ul>";
while (false !== ($file = readdir($dir_handle)))
{
$dir =$path.'/'.$file;
if(is_dir($dir) && $file != '.' && $file !='..' )
{
$handle = #opendir($dir) or die("undable to open file $file");
echo '<li><input name="" type="image" src="themes/default/images/explore/folder.png" />'.$file.'</li>';
list_dir($handle, $dir);
}
elseif($file != '.' && $file !='..')
{
echo '<li><input name="" type="image" src="themes/default/images/explore/file.png" />'.$file.'</li>';
}
}
echo "</ul>";
closedir($dir_handle);
}
?>
With the structure you have, a nested <ul> tree, this should be relatively easy.
Your folders all have <li> elements with anchors in them, not quite sure why as you have input-images inside them which are clickable in their own right. Put a class on these anchors or the input called "folder" or somesuch. Then all you need to do is hide all the ULs to start with apart from the root folder and use jQuery to show/hide the nested <ul> lists when a user clicks on the associated folder.
Providing you setup that "folder" class, try the following code.
/* if you want to hide all but the root with code */
$('ul:gt(0)').hide();
$('.folder').click(function() {
$(this).parents('li:first').next('ul').slideToggle('slow');
return false;
});