23 July 2007
You should be familiar with creating Dreamweaver recordsets, using the Spry table widget, and have a basic understanding of PHP. To get up to speed with PHP using Dreamweaver, read Setting up a PHP development environment for Dreamweaver by Charles Nadeau.
Intermediate
allow_url_fopen = onThis tutorial describes a rather uncommon, yet sensible approach to exchanging data between PHP and the Spry framework for Ajax. Both the tutorial and the ready-to-use demo application address the following functionality:
Figure 1 shows the related images ordered by ID and Figure 2 shows the images ordered by image. In the finished application, you will be able to click the Spry table's headers to change the sorting criteria
This tutorial is based on a fictious content management system (CMS) named "articles", where all images are stored in a common directory named "images" and each recordset has its related array of images stored in a unique subdirectory named after the recordset's article_id. For example, the first recordset (article_id 1) will store its related images in the subdirectory "1" (see Figure 3).
Create a new folder named adobe_xml_imagelist in your site's root and unpack the contents of the provided archive in this directory (adobe_xml_imagelist.zip). These sample files are linked to at the beginning of this tutorial. If they are installed correctly, the resulting directory and file structure should appear as in Figure 4.
The related MySQL table named adobe_xml_imagelist is really simple and has the following structure:
'article_id' int(3) unsigned NOT NULL auto_increment,
'article_headline' varchar(60) NOT NULL,
'article_content' text
For your convenience, the file articles.sql (located in the "sql" subdirectory in the sample files) can be used for adding this new table to your database plus inserting two related dummy records. When working with phpMyAdmin or another database administration tool, just use the import feature to, well, import this file. Otherwise, copy and paste the code from the articles.sql file into phpMyAdmin's "SQL" field.
Because several sample files, such as article_list.php and article_detail_dynamic_xml.php, are already preconfigured to query the adobe_xml_imagelist table and display the existing records including their related images, you need to create a new MySQL Connection named xml_imagelist.
The following instructions will, by design, not be covering every single configuration option. I would first like to run the preconfigured, ready-to-use sample application on your local testing server without worrying about initially nonessential details. I address these in the "Information for developers" section at the end of this tutorial.
Open the file xml_imagelist_servername_inc.php (located in the "scripts" directory) and change the default value of the following variable:
$http_servername_local = "http://localhost/guenter";
You will need to update the value of this variable according to your testings server's "URL prefix" settings, as defined in your Dreamweaver site's site definition (see the Testing Server category of your site definition).
Now it's time to test the application:
Important: By default this file assumes that the Spry libraries are installed in the <site root>/SpryAssets/ directory. If you install them somewhere else, you'll need to adapt the path manually in lines 47 and 48 (script src="../SpryAssets/xpath.js").
If you're interested in creating your own versions of the provided public pages (article_list.php and article_detail_dynamic_xml.php) and—as a side-effect—if you're eager to learn how to build the required database queries or insert/configure the Spry table, then this section of the tutorial is for you.
Trust me, at least it's interesting reading: Here is where you'll get a clue about the purpose of some previously unmentioned files (article_detail_sample_xml.php and xml_imagelist_testdata.xml) and where you'll be learning some essential details.
Note: Although it is, in theory, possible to save the following pages in any folder within your Dreamweaver site, I suggest saving them in the existing adobe_xml_imagelist directory. Doing so will certainly simplify matters when it comes to checking your file versions against the provided sample files, because the generated code of database queries or links to related files will be similar and, therefore, easier to compare. However, please don't forget to do a "Save As..." on your own productions under a different name.
Follow these steps to create the article_list.php file:
Selecting the table columns article_id and article_headline should be sufficient to build a simple article listing page.
In order to verify that this link has been correctly parameterized, click the cursor somewhere inside the "more..." link and click your right mouse button (Control-click on Mac) on the related <a> tag visible in the Dreamweaver Tag selector at the bottom of the Design view window. Click the Quick Tag Editor in the contextual menu. The Quick Tag Editor should display the following:
<a href="article_detail_dynamic_xml.php?article_id=<?php
echo $row_articles['article_id']; ?>">
May I call myself a soothsayer? At this point you'd rather expect me to explain how the article_detail_dynamic_xml.php page can be replicated, but there are two good reasons for elaborating on this page first:
For these reasons, I recommend building this page first and later saving it as a secondary "to become dynamic" version. Follow these steps to do so:
Because the to-be-displayed recordset will retrieve its article_id value from the previously explained article_list.php page, it's mandatory to define a correct filter condition:
"article_id" = URL Parameter "article_id"
Open the Application panel, click the Server Behaviors tab, click the plus (+) button, and select the Dynamic Text menu entry. As displayed in Figure 9, the recordset's article_headline, article_id and article_content placeholders should be inserted into the page.
Here comes the truly relevant exercise: adding the Spry table! However, a picture paints a thousand words. Figure 9 shows how your page should eventually appear in Dreamweaver:
Create a Spry XML dataset by selecting Insert > Spry > Spry XML data set:
I recommend leaving the options "Distinct on load", "Turn XML Data Caching Off", and "Auto refresh data" unchecked, as they will practically make no sense when loading the dynamically generated XML at a later time.
Next insert a Spry Table at the desired page position by selecting Insert > Spry > Spry Table. In the Columns panel, adjust the table columns by doing the following:
Applying some visual fine-tuning to the generated Spry table is easy by setting the table align to "center," as done in the provided sample page.
The XML values related to your Spry table's data references ({width}, {height}, and {filesize}) are stored and retrieved as integers, so I recommend that you add meaningful and familiar abbrevations such as these:
{width} px{height} px{filesize} kbThe default image tag generated by the Spry table is very basic (<img src="{url}"/>) and lacks additional attributes like "width", "height", and of course the mandatory "alt" and "title".
If you feel like adding them to the tag, click the "broken image" icon and switch Dreamweaver to Code view. You'll now see the above-mentioned basic image tag already highlighted. All you need to do is add the missing attributes and values like this:
<img src="{url}" alt="{name}"
width="{width}" height="{height}" border="0"/>
As you can see, assigning values to these attributes is simply a matter of copying and pasting already existing Spry data references you'll find elsewhere on this page.
Save this page, but leave it open.
Before previewing your article_detail_sample_xml.php version in a browser, you'll need to adapt the associated file, xml_imagelist_testdata.xml, to your local testing server environment. This XML file comes with three predefined data sets pointing to existing images located in the subdirectory images/2 and provides the following structure:
<imagedata>
<id>1</id>
<url>http://localhost/guenter/adobe_xml_imagelist/images/2/IMG_0019.gif</url>
<width>200</width>
<height>150</height>
<name>IMG 0019</name>
<filesize>27</filesize>
<filetime>04-07-2007</filetime>
<fileextension>gif</fileextension>
</imagedata>
While preparing this tutorial I admittedly didn't succeed predicting your Dreamweaver testing server's settings. That's why you need to replace the default "http://localhost/guenter" component of the image's <url>...</url> with your own testings server's URL prefix. Please do this for all three <imagedata> sets and save this file.
Now enjoy the results of your hard labor by previewing your article_detail_sample_xml.php page in your browser. You certainly deserve to have some fun now. If you agree with the displayed results, save it as article_detail_dynamic_xml.php.
As I promised before, making a dynamic difference to the previous page that's driven by static XML data will be a breeze. All you need to do is switch this page to Code view and look out for the following code block:
<script type="text/javascript">
<! --
var ds1 = new Spry.Data.XMLDataSet("xml_imagelist_testdata.xml", "imagelist/imagedata",{sortOnLoad:"id",sortOrderOnLoad:"ascending"});
ds1.setColumnType("id", "number");
ds1.setColumnType("url", "image");
ds1.setColumnType("width", "number");
ds1.setColumnType("height", "number");
ds1.setColumnType("filesize", "number");
// -- >
</script>
The above code block is located in the document's <head>...</head> section. Now replace the original file pointer:
var ds1 = new Spry.Data.XMLDataSet("xml_imagelist_testdata.xml",
"imagelist/imagedata",{sortOnLoad:"id",sortOrderOnLoad:"ascending"});
with this:
var ds1 = new Spry.Data.XMLDataSet("xml_imagelist.php?path_to_mediator=adobe_xml_imagelist&path_to_images=images/<?php
echo $row_article['article_id']; ?>", "imagelist/imagedata",{sortOnLoad:"id",sortOrderOnLoad:"ascending"});
Now that you've replaced this code, you're done!
Please remember: You will not be able to preview this page directly in your browser because it's not supposed to work in a standalone way. Always load your article_list.php page to pass one of the available article_id values to this page!
Unlike a regular Spry.Data.XMLDataSet, which usually retrieves values only from a given XML file containing given static data, an application that's supposed to retrieve image and file related data from "it depends" sources initially has no indication of the data's physical location—in other words, which folder to retrieve the images from—and doesn't know how to process the data. What a dilemma.
But rather than breaking out in a sweat, simply make PHP do the donkeywork for you and, furthermore, allow for an essential feature: a bidirectional exchange of data! As displayed in the data flow schema in Figure 11, the xml_imagelist.php script actually plays the decisive role as mediator between your page and the three underlying workhorses (xml_imagelist_applogic.inc.php, xml_imagelist_config_inc.php, and xml_imagelist_servername_inc.php), which are located in a separate scripts folder.
The "data source" parameter of the regular Spry.Data.XMLDataSet object is slightly modified to utilize a server-side scripting feature that's not available with static XML files: appending parameters to referenced PHP files.
In order to define the correct directory path (relative to your server root) to the desired image folder, you're sending a sequence of successive directory path information (also known as "directory drill-down") to xml_imagelist.php as URL parameters:
In this example, I'm pointing to an image directory located two levels below xml-imagelist.php. I know the first directory by name ("images"), but as the second directory depends on the currently effective "article_id" value retrieved from the recordset, I'll simply be using the related dynamic data "$row_article['article_id']" for the second directory.
I next combine the static and dynamic information to a valid file path: "images/<?php echo $row_article['article_id']; ?>"
Here is the complete directory drill-down specifications used in our sample file:
xml_imagelist.php?path_to_mediator=adobe_xml_imagelist&path_to_images=images/<?php
echo $row_article['article_id']; ?>
This file provides dual capacity by simultaneously doing the following:
Though doubtlessly playing a significant role, xml_imagelist.php has the only purpose of being a simple middleman. This means you can count yourself lucky to just make it require the necessary data processing (xml_imagelist_applogic_inc.php) and application configuration (xml_imagelist_config_inc.php) scripts:
<?php
require ('scripts/xml_imagelist_config_inc.php');
require ('scripts/xml_imagelist_applogic_inc.php');
?>
If you're a developer with some PHP knowledge, you might raise the legitimate question, "Why didn't you roll all functionality into one by throwing all data processing functionality in this file rather than spreading them across external files?" Good question.
This would indeed have been possible, but this separation allows for something important to users who'd like to go beyond the provided sample application and create their own "dynamic image list from directory" application. By using PHP's require function, it's a breeze to create an xml_imagelist.php derivate by just including a different configuration file, while keeping the xml_imagelist_applogic_inc.php file untouched (recommended, as you'll later see).
There's yet another benefit from outsourcing the configuration and application logic scripts: The whole scripts folder including, its contents, may also be moved to a different location on your server to allow for multiple scripts to access a centralized logistics. When creating your own mediator scripts, you'd just need to adjust their "require" file path specification to match the changed location of the scripts folder. Please note that the specified file paths are always relative to your mediator script!
As the schema in Figure 12 demonstrates, the provided application logic gives you a maximum of freedom regarding where the scripts folder and your Dreamweaver page may be located. But there's indeed one simple rule of thumb that says where your mediator script needs to be physically located (both apply):
While the technical requirement of having this file pointing to one or more subdirectories for grabbing the images may be obvious to experienced PHP developers—the @fopen function initially starts in the current working directory and then drills down to the directory specified in the path_to_images variable—some users might prefer to have this file located in the server root. Sorry, but this will not work because the application logic was designed to require at least one subdirectory below the server root. But isn't it great to be a skilled developer? You can change all that yourself .
This file contains three variables for defining your local and remote HTTP server name (let's call this "connection" for now) plus instructing xml_imagelist_applogic_inc.php, which "connection" is currently getting used.
This must equal the URL prefix specified in your Dreamweaver site definition:
$http_servername_local = "http://localhost/guenter";
This is required when running the application from your remote host:
$http_servername_remote = "http://www.domain.com";
This defines which of the abovementioned server names is currently getting used:
$http_servername_now_in_use = "a";
The options are:
"a": use local server name"b" or "": use remote server nameIn case you're wondering about the reason to determine a connection, because the generated XML data should be as portable as possible, you'll need to ensure an absolute file path (e.g., <img src="http://www.domain.com/adobe_xml_imagelist/images/1/logo.gif">) used for all images' SRC attributes, depending on whether you're running the application from your local testing server or from your remote website.
Besides including the previously mentioned connection file, this file contains eight variables, which are meant to control the general application behavior that's encapsulated in the script xml_imagelist_applogic_inc.php mentioned next.
The default values provided in this script do match the sample application's settings, which means you will not have to change them. Please note that the following explanation on the variables is also provided within the script itself.
This points to a specified subdirectory below your HTTP server root; it will also be used for assembling the correct image URL:
$subdirectory_initial = $_GET['path_to_mediator'];
Change this according to the file path declared in your Dreamweaver page:
$subdirectory_drilldown_below_initial = $_GET['path_to_images'];
It will be used for assembling the correct image URL. For example:
<img src="http://www.domain.com/adobe_xml_imagelist/images/1/logo.gif">
This is a comma-separated list of allowed file extensions (case insentitive!):
$allowed_extensions = array('.jpg','.jpeg','.gif','.png');
This affects the appearance of filenames: "Y" replaces underscores with spaces. Leave empty ("") to display the filename as is:
$filename_replace_underscores_with_spaces = "Y";
Filenames starting with a specified char will be excluded. Leave empty ("") to allow for all files:
$ignore_files_starting_with = "_";
This is the file last modified; change the display format according to your preferences:
$filetime_display_format = "d-m-Y";
Please read the PHP date() function page on the W3Schools website for more information on the PHP date() function and the variety of date-formatting options. Some commonly used international formats are as follows:
"d-m-Y": 31-12-1961"d/m/Y": 31/12/1961"d.m.Y": 31.12.1961 (the usual German format)This is an advanced option. Every time the Dreamweaver page containing the Spry table is launched, allow the referenced script (e.g., xml_imagelist.php) to additionally create a static XML file containing all the current nodes and values. Please specify the desired storage device in the following variable, $create_static_xml_file_in_directory:
$create_static_xml_file_on_pageload = "N";
This option defaults to "N" so just set it to "Y" to activate this feature.
The filename to be created is assembled using the following static and dynamic components:
"xml_imagelist")_)"news_1")".xml")Example: xml_imagelist_images_1.xml
$create_static_xml_file_in_directory
= "xml_data";
Specify the subdirectory (relative to the mediator script referenced from your Dreamweaver page) where the XML file(s) will be created. It defaults to xml_data. Hint: Set to "." to create the file in the script's working directory.
Note: Please enable write permission (e.g., 755) for the specified directory. Otherwise the file might not be generated!
This file is what I'd call the technology center; here is where the images from the specified directory:
And all of their related data will be rendered as dynamic XML.
XML structure generated on the fly
<?xml version="1.0" encoding="ISO-8859-1"?>
<! -- File generated: June 22, 2007 13:38:03 -- >
<imagelist>
<! -- dataset 1: start -- >
<imagedata>
<id>1</id
<url>http://localhost/guenter/adobe_xml_imagelist/images/1/2007-06-07_100_3691.jpg</url>
<width>250</width>
<height>188</height>
<name>2007-06-07 100 3691</name>
<filesize>14</filesize>
<filetime>07-06-2007</filetime>
<fileextension>jpg</fileextension>
</imagedata>
<! --
dataset 1: end -- >
<! --
dataset 2: start -- >
<imagedata>
<id>2</id>
<url>http://localhost/guenter/adobe_xml_imagelist/images/1/2007-06-07_IMG_1048.jpg</url>
<width>250</width>
<height>188</height>
<name>2007-06-07 IMG 1048</name>
<filesize>15</filesize>
<filetime>07-06-2007</filetime>
<fileextension>jpg</fileextension>
</imagedata>
<! -- dataset 2: end -- >
</imagelist>
Complete script code
<?php
if($create_static_xml_file_on_pageload == "Y") {
// Start buffering the dynamic XML data
ob_start();
}
?>
<?php
// XML IMAGE LIST FROM DIRECTORY: THE MAIN APPLICATION LOGIC
header('Content-type: text/xml');
header('Pragma: public');
header('Cache-control: private');
header('Expires: -1');
?>
<?php
echo('<?xml version="1.0" encoding="ISO-8859-1"?>');
?>
<! --
File generated: <?php print date("F d, Y H:i:s", time()); ?> -- >
<imagelist>
<?php
// DON'T EDIT ALL FOLLOWING CODE UNLESS YOU KNOW WHAT YOU'RE DOING ;-)
$a = '0';
$url_path
= "."; // means: look up files in specified target directory
$dir = dir($subdirectory_drilldown_below_initial);
?>
<?php
while($this_file=$dir->read())
{
if(in_array(strtolower(strrchr($this_file,'.')),$allowed_extensions))
{
if($this_file == "." || $this_file == ".." || substr($this_file,0,1) ==
$ignore_files_starting_with) {
continue;
// start looping
}
$fp = @fopen("$subdirectory_drilldown_below_initial/$this_file","r");
/************************************
check currently used http server name
************************************/
if ($http_servername_now_in_use == "a" || $http_servername_now_in_use == "A") {
$http_servername = $http_servername_local;
}
else
{
$http_servername = $http_servername_remote;
}
/************************
extracting the image size
*************************/
$img_size = getimagesize($subdirectory_drilldown_below_initial.'/'.$this_file);
$img_width = $img_size[0];
$img_height = $img_size[1];
/*************************************************************************************
stripping the extension from the file using the following "regular expression"
pattern:
1. a dot(.), followed by...
2. 3-4 chars to cover "jpg" or "jpeg"):
**************************************************************************************/
$friendly_filename = preg_replace('/\\.\\w{3,4}\\z/', '', $this_file);
/*************************************************************************
if the corresponding variable is set to Y, replace underscores with spaces:
**************************************************************************/
if ($filename_replace_underscores_with_spaces == "Y") {
$friendly_filename = str_replace("_"," ",$friendly_filename);
}
/***********************
extracting the file time
************************/
$filetime = filemtime($subdirectory_drilldown_below_initial.'/'.$this_file);
/**************************************************
extracting the file size and round it to an integer
**************************************************/
$filesize = number_format(filesize($subdirectory_drilldown_below_initial.'/'.$this_file)/1024);
/****************************
extracting the file extension
****************************/
$fileextension = end(explode(".", $this_file));
?>
<! -- dataset <?php echo $a+1; ?>: start -- >
<imagedata>
<id><?php echo $a+1; // numbering the loop, starting with "1" ?></id>
<url><?php echo $http_servername; ?>/<?php echo
$subdirectory_initial; ?>/<?php echo
$subdirectory_drilldown_below_initial; ?>/<?php echo $this_file; ?></url>
<width><?php echo $img_width; ?></width>
<height><?php echo $img_height; ?></height>
<name><?php echo $friendly_filename; ?></name>
<filesize><?php echo $filesize; ?></filesize>
<filetime><?php echo (date($filetime_display_format, $filetime)); ?></filetime>
<fileextension><?php echo $fileextension; ?></fileextension>
</imagedata>
<! --
dataset <?php echo $a+1; ?>: end -- >
<?php
$a = $a + 1;
}
}
?>
</imagelist>
<?php
if($create_static_xml_file_on_pageload == "Y") {
/*****************************
Get the contents of the buffer
*****************************/
$buffer = ob_get_contents();
/****************************************************
Stop buffering and allow writing the XML data to file
****************************************************/
ob_end_flush();
/*****************
write the XML file
*****************/
$current_scriptname = preg_replace('/\\.\\w{3,4}\\z/', '', basename($_SERVER['PHP_SELF']));
$cachefile_filepath = str_replace("/","_",$subdirectory_drilldown_below_initial);
$cachefile_name = $create_static_xml_file_in_directory."/".$current_scriptname."_".$cachefile_filepath.".xml";
$fp = fopen("".$cachefile_name."", "w");
fwrite($fp, $buffer);
fclose($fp);
chmod (''.$cachefile_name.'', 0755);
}
?>
Besides trying to explore yet another real-world application and hoping that approach and result is considered useful by other developers, I wrote this tutorial primarily to illuminate one of Spry's comparatively undervalued capabilities: Its openness to have inquiring developers easily add behaviors by using their familiar server-side scripting language skills.
Of course, none of the illustrated methods can honestly be considered virgin soil, if you look at them separately. Everyone knows that the Spry framework for Ajax, as such, is meant to handle XML data, and learning how to grab file contents from a directory belongs to any PHP developer's basic skills.
Something unexpected dawned on me while I was developing the application. It might not be the most consummate thing there is, but it's indeed a good example of "give and take" between technologies. This is not the ordinary XML one-way street, and the functional benefits are mutual.
Some features of this application would, in real life, certainly qualify as a "because you can" feasibility study rather than a realistic endeavor. If you were to develop this for your customer, image sorting criteria like "by file size" certainly wouldn't make sense within the context of a "related slide show" CMS module. But you can, that's why you're a developer, right?
So, where to go from here? In theory, there are many options at your disposal besides improving the provided application or extending features as you see fit. This idea alone can very easily be adapted to build dynamic "related files" listings rather than images, and it will certainly be interesting to explore how this conception can be extended to embrace other features like Spry paging (introduced in version 1.5).
I hope this tutorial has a welcome side-effect: encouraging you to be innovative and adventurous when it comes to building a bridge between things—in the best Adobe tradition. Cheers! ;-)
Tutorials and samples |
| 04/23/2012 | Resolution/Compatibility/liquid layout |
|---|---|
| 04/20/2012 | using local/testing server with cs5 inserting images look fine in the split screen but do not show |
| 04/18/2012 | Ap Div help |
| 04/23/2012 | Updating |