Reputation: 4964
I have a Projects page with a content area and a sidebar. I want the sidebar to contain a dynamic list of projects. The content area has an div with the id "post".
I have a subfolder containing .php files corresponding to projects that contain html content about each project.
I would like the sidebar to generate an unordered list based on the filenames of the php files (or if possible, an h1 element inside each php file).
When clicked, I would like each of the items in this unordered list to populate the div id "post" in the content area with the contents of the php file to which it corresponds.
I know it would be easier with a CMS like Wordpress, but I want to know how to do it without an SQL database if possible. Keep in mind, I know almost nothing about PHP. I have stuck to html/css so far.
Upvotes: 1
Views: 696
Reputation:
# index.php
<?php
if( $files = glob('/path/to/directory/*.php') )
{
?>
<ul id="sidebar">
<?php
foreach( $files as $path_raw )
{
$file_raw = basename($path_raw);
$file_safe = htmlentities($file_raw);
$file_urlsafe = urlencode($file_raw);
?>
<li><a class="file-link" href="/post.php?file=<?php echo $file_urlsafe; ?>"><?php echo $file_safe; ?></a></li>
</ul>
<?php
}
To locate the files, we will want to use glob()
. In this case, pass in a path to a directory (/path/to/directory
) and a filename pattern (*.php
) to find all '.php' files in the specified directory.
glob()
returns an array, so we will need to iterate over the result using foreach
.
Since we are providing an absolute path to the directory where the files are located, glob()
will return an array of absolute paths, so we will need to use basename()
to strip off the directory info and just get the filename.
Although unusual, it is possible for filenames to have unsafe characters in them, so we need to escape the values using urlencode()
for URL strings (the href
for the anchor tag) and htmlentities()
otherwise (the text of the anchor tag).
The link in the unordered list references a file named post.php
under the web server's document root.
# post.php
<?php
$basedir = '/path/to/directory';
if( empty($_GET['file']) )
{
// Handle error condition: no filename provided.
}
$file_raw = $_GET['file'];
$file_safe = basename($file_raw);
if( ! is_file($file_safe) )
{
// Handle error condition: file does not exist or is not a file.
}
elseif( ! is_readable($file_safe) )
{
// Handle error condition: file exists, but is not readable (probably permissions issue).
}
passthru($file_safe);
post.php Expects a $_GET
value named file
to be provided (taken care of by clicking on one of the links in the sidebar). It is important to note a couple of things:
file
value might be missing (we can check for this by using empty()
).file
value might have a different value than we were expecting (in this case, we will use basename()
to ensure that we are dealing with a filename and not an injected path).file
value is valid, it might reference a path that is not actually a file, or it points to a file that the webserver cannot access (we check for these cases by using is_file()
and is_readable()
, respectively).Finally, once we are sure that the file
value points to a valid file, we send its contents to the web browser using passthru()
.
The only thing left to do is to use some Javascript so that clicking on one of the sidebar links displays the contents in the #post
div. I will use jQuery here for brevity:
# index.php
(function($){
$(function(){
var post = $('#post');
$('#sidebar a.file-link').click(function( e ){
post.load($(this).attr('href'));
e.preventDefault();
});
});
})(jQuery);
This code leverages the .load()
method, which executes an ajax call and replaces the selected element with the content from that request.
We use .click()
to set the ajax call to only trigger when the user clicks on one of the links in the sidebar, and we determine which URL to go to by calling .attr()
on the clicked link to extract its href
attribute.
Note that we use the event's preventDefault
method rather than returning false
to avoid potential for unwanted side effects.
Upvotes: 0
Reputation: 17344
The Solution:
function getfiles($dir){
if(!is_dir($dir))
return false;
$dirhandle = opendir($dir);
$files = array();
while($entry = readdir($dirhandle)){
if($entry!='.' && $entry!='..' && !is_dir($dir.'/'.$entry))
$files[]=$entry;
}
return $files;
}
Returns an array of the files. There are three special entries in a directory that aren't files. .
refers to the directory it's in. ..
refers to the parent directory. Finally, there are other directories. So far as I know, everything else is a file.
And then:
function createlist($dir){
if(!$files=getfiles($dir))
return false;
?>
<script type="text/javascript" >
function getcontent(xthis) {
var httpRequest;
makeRequest(xthis.href);
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
return false;
}
httpRequest.onreadystatechange = putContents;
httpRequest.open('GET', url);
httpRequest.send();
}
function putContents() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
document.getElementById("post").innerHTML=httpRequest.responseText;
} else {
return false;
}
}
}
}
</script>
<?PHP
echo "<ul>\n";
foreach($files as $file){
echo "\t<li><a onclick=\"getcontent(this);return false;\" href=".$dir."/$file>$file</a></li>\n";
}
echo "</ul>";
return true;
}
Ajax functions courtesy of https://developer.mozilla.org/en/AJAX/Getting_Started.
Upvotes: 1