[Top]
   
Look at also other topic groups, which I have done!
You can return to this topic group by using this menu and the link Table of topic groups in the top of the page.
 
 
Search:
[Help]
To the normal page

Dynamic structure with PHP

Topics

I have divided this page into sections, which handle following topics:

The content as a one big page

Common

It is always reasonable to define presentational details with CSS. It is also possible with CSS to separate at some level presentation and contents from each others. Ordinary Web-documents have always necessary structural parts, which don't belong to the actual contents. Basic navigation elements don't belong to the actual content. It is however possible to divide page into fragments, which the server builds an entire document.

PHP is one possible server-side language to do this. PHP was originally known as Personal Home Page Tools by by Rasmus Lerdorf. PHP is a HTML-embedded scripting language. Much of its syntax is borrowed from C and Perl with a couple of unique PHP-specific features thrown in. The goal of the language is to allow web developers to write dynamically generated pages quickly.

Below is a list of some such common features with other programming languages, which are important in order to understand examples, which I have in this page:

PHP-encoding has been separated from the other content usually with <?php + ?> or <? + ?> tags (at least in XML-document should use the longer format). Also Microsoft's ASP (= Active Server Pages) style tags (<% + %> & <%= + %>). Even if the file would not have anything else than PHP-encoding, PHP must be enclosed with PHP-tags. PHP can be run in all most used server applications.

Servers must identify pages, which use PHP. That's why the final pages must use certain file extension. In general servers has been defined so that they interpret *.php, *.php3, *.php4 and *.phml files as files, which need the PHP-parser.

Server and editor-specific notes:

  1. In principle it is also possible to use <style language="php">...</style> style tage, but they might cause difficulties for editors because they don't necessary interpret them as PHP-tags.
  2. Many servers don't support as default ASP-style tags. If they are intended to use, the support must ask from the webmaster of the server. The function phpinfo() informs the setting of the server.
  3. If other than the file extension .php has been used supported file extensions must check from the administrator of the used server or they must be tested before wide usage. At least in Apache-server supported file extension has been defined in the configuration file of the server. File extensions php3, php4 and phtml are such that they are not recommend to use because they are deprecated file extensions.

If files, which use PHP have been used as embedded in pages, which use PHP, the file extensions of embedded files can be set freely. These kind of pages could be called as "slave documents", which are never used as stand alone but always as particles of other Web documents. Pages which visitors see in the Internet could then be called as "master pages". The common habit is to use for slave documents the inc prefix (for example includeTop.inc).

Thinking about the download time of Web-page server-side scripts have advantages and disadvantages. The are good for slow computers because the server run scripts. In the other in fast computers and busy servers scripts, which are executed by the browser might work faster. In general server-side script are more reliable and it is necessary to think differences of browsers.

For me PHP is free with basic tasks. For many amateurs PHP is the only possibility to create cheap relative dynamic pages. If I would use databases I should page extra charge. I have experimented database-based Web-designing in my own computer. I try to apply the basic ideas of database-based Web-designing. I don't handle PHP very thoroughly. Understanding of examples in this page might need to read thorough PHP guides. I have learned most features from the PHP Manual, which is edited by Stig Sæther Bakken.

PHP: Download documentation.

[Top]

Getting fragments

Topics

Functions, which get fragments

Fragments have been gathered together by using either readfile(), include() or require() functions. The file is normally inside parenthesis but concerning require quotation marks (' or ") are enough (for example <?php require(some.inc';?>). In addition it is noticeable that include(') should be enclosed with a curly brackets ({ + }) using statement block if it is inside a conditional block.

In addition of these function is needed for basic output the function print() or echo(), which either write a new code or print the brought code into another place. In the latter case the code has been defined as a variable. Below is an example of using a variable in order to print a string:

<?php $Variable="\"This is the text, which the should be printed by using a variable\"";
print $Variable;?>
prints the following text:
"This is the text, which the should be printed by using a variable"

The string could have ordinary text or for example HTML-code. If the string has single or double quotation marks it is necessary to put a backward slash (\) as the escape character before quotation marks. Otherwise the PHP-parser would interpret quotation marks either terminating the string or diving the string into pieces. If the string would have divided into pieces between sub-strings should be a dot (for example "string"."string"), when the string would be concatenated.

In some is necessary use so called arrays, which has several particles, for example:

$aLinks = array('Link1.inc','Link2.inc','Link3.inc');

Functions, which include fragments into main document should use so that the server would use as fast as possible but functions have also their special problems. Below is some basic information:

Server-related notes:

  1. All servers don't support the readfile() function.

  2. If the server founds an error, when the require() has been used and the required file can't be found, the server stops immediately downloading the page. If the include() would have used instead, the server could skip the error. It is the most safe to use the include() function.

  3. Servers have different error message printing. It might be impossible to debug all server errors online.

  4. With certain settings of the working mode and open_basedir relative references don't work. If pages are necessary to test offline it is necessary to think thoroughly reasonable naming conventions and put most included files to the same folder. Each data type could be searched by using file masks (for example *index.inc).

  5. Servers might also prevent using absolute paths (http://...), when it is impossible to share PHP-files with several folders.

[Top]

What parts have been used as fragments

At least following fragments would be reasonable:

I had in the page DynamicMenus.php3 have once been the following structure (I have added comments):

<?php
/* The top part of the page: */
readfile('AdviceMeta.inc'); /* The generic beginning until the common HEAD-section. */
require ('DynamicMenus0Top.inc'); /* Page level HEAD-section and the start-tag of the BODY element.
/* The beginning of the BODY-section: */
readfile(topSection.inc'); /* Immediately after the start-tag of the BODY-element existing common part of the BODY-section. */
require('dynamicMenusButtons.inc'); /* Page level navigation buttons. */
readfile('AdviceOldInfo.inc'); /* Generic information for old browsers. */
/* Common navigation elements in the top part of the BODY-section: */
readfile('AdviceHideInst.inc');
require (allPages4.inc');
requre ('AdviceNavigation.inc');
/* The content-related parts of the BODY-section: */
print "<div class=\"doc\" id=\"docSection\">"; /* The start-tag of the surround the actual content existing basic structural element. In some pages this is a part of the actual content of the page. */
require ('DynamicMenus0Content.inc'); /* The actual content of the page. */
/* Parts, which concern terminating the page: */
readfile(nextSection.inc'); /* Two navigation buttons (to the top of the page and to the next page). */
print "<br /></div>"; /* The end-tag of the structural element, which was written around the actual contents. */
readfile(bottomShort.inc'); /* The final termination of the page including termination tags for BODY and HTML elements. In some page the page I have advertisements and announcements before termination tags. */
?>

Some fragments can think as as if modules. In the example above all browsers get the same modules. It is also possible to tailor modules for different browsers (I handle browser-detections further).

Details

In page-level META tags a part of the content is common and part page-specific. For example before the page-specific description is the generic description of the sub-site:

<meta name="description" content="<?php readfile(metaContent.inc');?>..." />

I have made with PHP + JavaScript very effective way to control relative navigation links (up, prev and next) by setting to the HEAD-section:

<link rel="prev" href="javascript:prev();" />
<link rel="next" href="javascript:next();" />
<link rel="up" href="javascript:up();" />
...
<script language="JavaScript1.1" type="text/javascript">

<!--
function up(){
open("index1.php3","_self");}
function prev(){
open("Linkkeja.php3","_self");}
function next(){
open("index2a.php3","_self");}
//-->
</script><style type="text/css">
...

And into the BODY-section:

<body...>
...
<td align="left" style="width:16px !important">
<a href="javascript:prev();" onmouseover="window.status='The\ previous\ page\ or\ anchor';return true;" onmouseout="window.status='';return true;" class="left" title="The previous revious page or anchor"><img
src="../Kuvat/buttons/Left.gif" border="0" alt="[Prev]" align=
"middle" style="height:16px; width:16px" /></a>
</td>
<td align="center" class="up">
<a href="javascript:up();" onmouseover="window.status='To\ the\ upper\ page\ level';return true;" onmouseout="window.status='';return true;" class="up" title="To the upper page level"><img
src="../Kuvat/buttons/TopSmallDouble.gif" border="0" alt="[Up]" align=
"middle" style="height:16px; width:16px" class="up" /></a></td>
<td align="right" style="width:16px !important">
<a href="javascript:next();" onmouseover="window.status='The\ next\ page\ or\ section';return true;" onmouseout="window.status='';return true;" title="the next page or section" class="right"><img
src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="middle" style="height:16px; width:16px" /></a>
</td>

...
<?php readfile('nextSection.inc'); ?>
</div>
</body>
</html>

In the nextSection.inc is the following HTML-code:

<div style="margin-top:1.0em"><div class="cNoPrint"><a href="#Top"><img
src="../Kuvat/buttons/Top.gif" border="0" alt="[Top]" align="middle" title="To the top of this page"/></a><br /><br /></div>
<div class="noPrint noBig" align="right"><a href="javascript:up()"><img
src="../Kuvat/buttons/TopSmallDouble.gif" border="0" alt="[Up]" align="middle" title="To the upper page level" /></a> <a href="javascript:next();"><img
src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="right" title="The next page or section" /></a></div><br /></div>

The disadvantage of using JavaScript is that the JavaScript-support must be enabled. The same functionality could be achieved by using only PHP for example at the following way (as an example going from the page Elementit0.php3 to Elementit.php3):

  1. Before the actual link set would be information about page-level variables (I would put them into the HEAD-section of the current document):
    <?php
    $next = "Elementit.php3";
    $up = ...
    ?>
  2. If the LINK element has been used, with PHP will generate attribute values from variables, for example rel="up" href="<?php print $up;?>"
  3. The link set in the bottom of the page will be included at the ordinary way by using <?php require ('...');?> or <?php include ('...');?>.
  4. The included file has link addresses, which are defined elsewhere by using variables. It could be like in two examples below:
    <?php print "...<a href=\"".$next."\"><img src=\"../Kuvat/buttons/Right.gif\" border=\"0\" alt=\"[Next]\" align=\"right\" title=\"The next section\" /></a>"; ?>
    or
    ...<a href="<?php print $next;?>"><img src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="right" title="The next section" /></a>

Variables can be written also inside funtions and call assosiated functions, for example:

<?php
function nextSection(){
$next=...
print $next; /* Variables don't work if they have defined outside the function if they have not explicit declared within the function as global variables (for example global $next, ...;). */
...
}

...
<a href="
<?php nextSection();?>"> ...

The easiest way is to predefine variable and if necessary variables have been in page level redefined. In all cases it is not necessary to redefine all variables in individual pages. It is however necessary to remember that variables takes the values, which are last defined before the associated functions. The following code doesn't work in any browser:

<link rel="up" href="<?php up();?> />
<?php
$up = "Content.php";
function up(){
global $up;
print $up;
}
?>

In that example I have marked links as variables. I handle using variable more in the next section.

[Top]

Effective usage of variables

Topics

The basic idea of using variables and naming conventions of variables

The basic idea of PHP-variable is that they can be defined elsewhere than the place, where they have been used. In the example in the previous section I have defined them in the same page, which resemble the usage of the STYLE element.

If variables has been defined totally outside the master pages, the usage resemble using the @import at-rule in CSS, where the imported file is as if written to the current page.

Because both ordinary variable and and arrays have been needed one of my e-mail friend proposed that I should use following naming conventions, when in future could be at once see, what it the type of the variable:

Because string variable is the most used variable type, I don't set for ordinary string variables any prefix. Use mixed case (humorous "camel case") characters (for example $aMyArray), underscores (for example $a_my_array) or combination of previous mentioned naming types (for example $a_My_Array) in order to get names more readable.

[Top]

Repeated strings

All fragments can be written as separate files but small fragments are reasonable to put as variables. If pages has been alphabetic listed, but the order of pages might change or more pages might be added in future, it is reasonable to set the characters of the pages as string variables. When the order has been changed, it is necessary to edit much fewer pages. Variables can be used several times in a page. For example in the page, which handle dynamic menus I have used the same variable four times:

Link lists

In one of my previous example I handled pagelevel variables. Also link lists are reasonable to put as variable. Links can be sorted beforehand. By using sort() (from first to last) and asort() (from last to first) in order to sort links alphabetically the sorting base on the string of variables not on the name of the variable.

In order to get the desired result I have set for links class-attributes. For example

<?php
$CodeStyle ="<a class=\"CodeStyle\" href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>";
...
$aLinks = array($..., $..., $CodeStyle, $...);
sort($aLinks); /* The link http://www.codestyle.org becomes now first. */
?>
can be called ready sorted in other connection, where PHP generates the final link list, for example:
<ul>
<?php
include(../tutorials.inc';

for ($i = 0; $i < count($aLinks); $i++) /* Counting of the loop starts from zero. In each round the value increases with one until the counter finds that the loop has been reached the last variable. It is possible to use for arrays also the foreach function, which is a predefined array looping function. It converts arrays to string variables (for example foreach($aLinks as $someVariable)), when it is not necessary to use a counter. */

{
print ("<li>".$aLinks[$i]."</li>\n"); /* If we had used the foreach function the name of the variable would be the given new name, for example $someVariable. In this case it is necessary to use double quotation marks. If you use "..." you can insert variables into the string and have the output be the value of the variable. If you would use '...' the exact characters in the string will be printed out, not the value of the variable. It is not necessary to use the concatenation operator in the format ("<li>$aLinks[$i]</li>\n"). */
}
?>

</ul>

In principle it would logically be more reasonable to use the attribute id but the problem is that in the same page should never be the same value of the id attribute more than one. There might be situations, where the same link has been used several times in a page.

If I would not have used the class-attribute generating alphabetic order would have needed defining special keys. I have however tried to keep the system as simple as possible. Below is however a modified example on the base of a model from one of my e-mail friend:

$aLinks = array(
"CodeStyle" => "<a href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>",
...
);

At this way can create link files, which resemble link databases and which are easy to edit. In the example above organizing list and the final generating resemble data base managements but link-related individual variables must manually list inside the used array.

If link-related variables has directly been defined inside an array at the way below it is possible to get the whole array or an individual member of the array. Updating the array and adding more link-variables can be done together and updating the array doesn't cause any additional work.

<?php
$aLinks = array(
($CodeStyle ="<a class=\"CodeStyle\" href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>"),
($IndexDOTCss="<a class=\"IndexDOTCss\" href=\"http://www.blooberry.com/indexdot/css/\" target=\"new\">Index DOT Css</a>"),
...
);
?>

If it is necessary to create a new array, which has more individual variables than some existing array, new variables can be added to an existing arrays, which become a part of the new array. Below is an example of a new array, which have been create by using the array_push() function. The new array has one variable more than the previous created array.

<?php
$aLinksFi = $aLinks;
array_push($aLinksFi,
($KeijoKortelainen="<a class=\"KeijoKort\" href=\"http://www.2kmediat.com/\" target=\"new\">Keijo Kortelainen, 2K mediat</a>")); /* The used function add a new variable into the end of the existing array. */
?>

In my case the same result could have get by using the function array_unshift(), which put new variable in the beginning of the array. With the function array_merge() can be combined two or more arrays. In this example case the variable $KeijoKortelainen should have first set inside a new array.

Defining variables inside arrays has one disadvantage. If variables, which are inside arrays have been redefined, redefinitions don't concern arrays.

In order to get new values for variables, which are inside arrays, original variables inside arrays must remove and replace with changed variables by using the array_splice() function, for example:

$TopStyle=$TopStyle." (".$BradSoft.")";
$PageBuilder=$PageBuilder." (".$TafWS.")";
$DHTMLMenuB=$DHTMLMenuB." (".$xFX.")"; /* In the original $aApplications array previous listed variables have different values. */

array_splice($aApplications,2,3,array($TopStyle,$PageBuilder,$DHTMLMenuB));
/* Parameters 2,3 remove original variables. */

The function array_splice() remove the elements designated by offset and length from the input array, and replaces them with the elements of the replacement array, if supplied. It is not possible to remove variable by the names of variables. That's why it is always necessary to check offsets of removable variables and removable variables should be after each other in order to remove them with one command. That is in my mind the biggest disadvantage.

By using real databases links can be get by using names of fields. Because values have not been written directly inside arrays, local changes concern also arrays. Using the previous mentioned system adding new links into a link list is however approximately as easy as by using real databases. Below is an example of using databases, which should get the same result as one previous handled example getting data from an included file:

<ul>
<?php
$result = mysql($conn, "SELECT class, address, name FROM tutorials"); /* Lets presume that the used database table has fields id, class, address name and description, which in this example has been fetched information from three fields. */
while (list($class, $address, $name) = mysql_fetch_row($result)) {
print("<li><a class=\"$class\" href=\"$address\" target=\"new\">$name</a></li>");
}
?>

</ul>
[Top]

DynamicMenus

I have made dynamic menus quite static. They can be generated also dynamic with PHP. Compared to JavaScript encoding the advance is that menus exist even if the JavaScript support has been disabled.

The end and bottom of the dynamic menus is reasonable to write as ordinary HTML and or write it with functions. Functions are not however necessary in this purpose.

Menu items

Functions are always needed only in generating menu items. PHP generates the structure of menus items and the content of each menu item has been defined elsewhere by using variables. For example the following mItem() function generates sub-menu items:

function mItem(){

global $classD,$idD,$mOver,$classD2,$classA,$idA,$title,$href,$name;

print "<div class=\"".$classD."\" ".$idD." onmouseover=\"".$mOver."><div class=\"".$classD2."\"><a class=\"".$classA."\" id=\"".$idA."\" title=\"".$title."\" href=\"".$href."\"\">".$name."</a></div></div>";
}
Using individual global variables

In this connection has been used individual global variables. Variables don't need to list neither inside the argument lists of the function definition nor function calls. All variables are not necessary to define but if some of them has been defined the defined value concerns automatic all preceding function calls if variables has not been redefined. In the end of the function definition file can be set some default values and a function, which resets default values, for example:

$classD="noArrow";
$classD2="itemD";
$idD=""; /* The value of the variable must write in the format $idD="id=\"idValue"\"; because the value must be unique and empty value is illegal. The default value can't be empty attribute but instead not at all attribute. By Other variables generated id-attributes are such, which have been generated for all elements and the author must always set unique values for them. This problem can be avoided by using an additional function (I have later a model how to do that). */
$classA="itemA";
$mOver="";

function setDefaults(){

global $classD,$idD,$classD2,$classA,$mOver;

$classD="noArrow";
$idD="";
$classD2="itemD";
$classA="itemA";
$mOver="";
}

Below is an example, which defines a sub-menu. Because the definition has an exceptional class values in the end is the function, which returns original values:

$idA="uniqueId";
$title="Some link";
$href="link1.php";
$classD2="someClass";
$name="Link 1";

smItem();setDefaults();

I define in general four from the nine variables, which define attribute values. For example

$idA="CSSCover";
$title="CSS-oppaan aloitussivu";
$href="
index1.php3";
$name="Aloitussivu";

mItem();
generates together with the function mItem() the following final source code:
<div class="noArrow" ><div class="itemD"><a class="itemA" id="CSSCover" title="CSS-oppaan aloitussivu" href=" index1.php3" onmouseover="">Aloitussivu</a></div></div>

Instead of listing variable before the function call they could also be set inside function calls separating variables with commas (mItem($idA="CSSCover",...)).

The problem of the code above is that it generates much empty onmouseover attributes. They can be taken off with more complex encoding, but this is not essential. Concerning those attributes and some id attributes it could be possible to check, if variables are empty. If they would be empty, attributes would not be generated at all. Otherwise would be printed attributes and values of the attributes. Below is the code to implement this:

checkIfEmpty(){

	global $mOver,$idD;
	
	if (empty($idD)){ } /* The function definition can be empty. */
	
	else {
		print " id=\"".$idD."\"";
	}
	
	if (empty($mOver)){ }
	
	else {
		print " onmouseover=\"".$mOver."\"";
	}
}


function mItem(){
...
	print "<div class=\"".$classD."\"";
	checkIfEmpty();
	print "> class=\"".$classD2."...";

Using arrays

The system, which I have proposed above doesn't follow in one respect recommended programming conventions. The information of variables leak leak from one target to another targets. Instead of using individual variables could be use an array (for example $aItem) and for sub-variables (they are inside brackets), which correspond above used ordinary variables at the following way:

function mItem(){

global $aItem;

... ".$aItem["classD"]." ... ".$aItem["href"]." ... ".$aItem["name"]"...

Values of sub-variables could be defined with the following way by using the => operator:

mItem($aItem = array("classD" => "noArrow", ..., "href" => " index1.php3", "name" => "Aloitussivu", ... ));

Now values of individual variable don't leak but the disadvantage is that all individual values must be redefined inside the array. Of courser it is possible to use functions, which check if attribute values are empty (they are empty if values has not been set at all) and if they are empty predefined default values has been set. In my mind would be more reasonable to create an own array for non-empty default values, for example:

$aItemDefaults = array("classD" => "noArrow", "classD2" => "itemD", "classA" => "itemA", "href" => "#");

These default values can be combined with the array $aItem by using the function array_merge(). Below is an example:

mItem(array_merge($aItemDefaults,$aItem = array(
"idD" => "GenericItem",
"idA" => "GenericA",
"classD" => $arrow,
"title" => "Generic",
"mOver" => "hideThlMenus(); MM_showHideLayers('indexPages','','hide','allSites','','hide','Generic','','show'...);"
)));

If values are different values of the latter array wins. In the case above "classD => $arrow" wins the default setting "classD" => "noArrow".

In all previous mentioned example usages of arrays have been created more code than using individual variables. Indeed I have seen compressed JavaScript arrays, where arrays have been defined so that the user must only add information between commas (for example ,,,noArrow,,,). I believe that it could be possible to create the same kind of solution also by using PHP. The problem of those kinds of solutions is that it is difficult to remember, what value belong between each comma. That's why I don't recommend to use so compressed code. In my mind the easiest system for amateurs is to use individual variables. Maintaining complex arrays is for professionals.

Container blocks

The container elements of sub-menus is reasonable to set at least one variable, which sets an unique id-attribute for the sub-menu. In the example below I have used individual variables (also arrays could be used):

function smTop(){

global $id,...;

print "<div id=\"".$id."\" class=\"pageGroup\"...
}

The related function call is the following:

...
$id = "MainPages";

...

smTop();

With these solution it is possible to automatise generating menu items, but generating menu blocks and the entire menu is just partially automated.

Presentations

I have defined almost all presentational features in outside CSS-files. The most remarkable exception is that I have defined the height of some elements by using PHP and style attributes. The author defines the content height of the sub-menus by using the variable $iHeightMI (the name comes from words integer Height Menu Items). That content height defined also height of shadows (height values might be today a little bit different):

function smTop(){

global ...,$iHeightMI;

print "<div id=\"".$id."\" class=\"pageGroup\" style=\"height:".($iHeightMI+10)."px;\">
...
}

function smBottom(){

global $iHeightMI;

print "</div><div class=\"shadowBase\" style=\"height:".($iHeightMI+122)."px;\"><div class=\"shadow\" style=\"height:".($iHeightMI+18)."px;\"> </div></div></div>";
}

The weakness of this solution is that the author must manually set the value of the variable $iHeightMI. If a sub-menu would be an array, it would be possible to count the quantity of array items. That values should be multiplied with the value of the height of one menu (in my case the value is 15px). There are a lot of other presentational features in my solution which could be automated.

The positioning of all menus has been defined in the beginning of the ../Css/dynamicMenus.css[S] CSS-file. It defines also generic presentational features of dynamic menus. It is easy to edit the CSS file so that the main menu is either vertical or horizontal.

Because I have used dynamic menus also as static link tables, setting menus inside table cells and rows can't be done automatic by using PHP-functions. If dynamic menus are not needed as static link tables, all menu blocks related elements can be generated by PHP-scripts.

I made for one menu a template[S], which is related with the definition file of used functions as a text file[S]. If you don't need table cells around menus, delete all source code, which are related with table elements (TABLE, TR and TD).

By using CSS + PHP it is possible to separate from each others the basic structure, presentational details, JavaScript-encoding and the content of sub-menus.

With some further evaluation my solution can be converted using databases, where the values of generated attributes have been get from databases instead of *.inc files. If each menu is an own table, it is possible to fetch the whole content of a table and then for example by using the while-loop and list() at the following way:

<?php
result = mysql($conn, "SELECT classD, idD, mOver,... FROM menutableMain");

while (list($idA, $name,...) = mysql_fetch_row($result)) {
print ...

}
?>

Special headers and empty menu items must however forgot because they would interrupt handling of loops. Or they must be build at the same formula, where ordinary menu items has been build.

It is possible to create a form, which the menu can be updated by using any Web browser. Some form fields should be required and some other implied. I don't have - at least just now - skills to do that. And If I had I would not handle database usage in my pages.

If dynamic menus seems to be downloaded too slow, menus can precompile by making a new *.php file, which PHP compiles. The compiled menu file can be saved with it original name, but into another folder. From that folder the compiled file can be sent into the Internet.

[Top]

Browser detections

The basic problem detecting browser with PHP is that only User Agent strings can be detected by using the predefined variables, for example $HTTP_USER_AGENT.

<?php print $HTTP_USER_AGENT; ?>

The function above prints the UA string of your browser if the settings of the server allows it. It is however to better to define a new variable for that, for example $userBrowser = $_SERVER['HTTP_USER_AGENT']; (I use variable $userBrowser in my examples).

Server-specific notes:

  1. In the settings of the PHP-parser might be register_globals=Off. In that case $HTTP_USER_AGENT doesn't work. $HTTP_USER_AGENT etc. are build-in application-level variables, which can normally be used in any situations. When the author defines variables by using the keyword global they concerns the page, where the script has been used (by using for example the include function it is possible to emulate application level variables). By using the $_SERVER variable it is possible to create new script-level global variables. For example the code

    <?php
    global $userBrowser;
    $userBrowser = $_SERVER['HTTP_USER_AGENT'];
    print $userBrowser;
    ?>
    should print the UA string of your browser, which you can see below:
    CCBot/2.0 (http://commoncrawl.org/faq/)

One of the most problematic browsers to detect are Netscape 4.x series browsers. The only string, which can be used is Mozilla and the version number of it. Below is a user agent string of a Netscape 4.x browser:

Mozilla/4.79 [en] (Win98; U)

The string Mozilla/4. use almost all browsers in the market and other browsers should be able to shut off. Below is a code, where by using the function stristr() has been detected MS IE, Opera and Mozilla Gecko browsers and the string Mozilla/4 (using this functions name are not case-sensitive).

$MSIE = (stristr($userBrowser, "MSIE") || stristr($userBrowser, "Internet Explorer"); /* The first argument of the function stristr is the string, where the sub-string should be found. The second argument is the searched sub-string. */
$Opera = stristr($userBrowser, "Opera");
$Moz4 = stristr($userBrowser, "Mozilla/4");
$Gecko = stristr($userBrowser, "Gecko");
$NN4 = ($Moz4 && !$MSIE && !$Gecko && !$Opera);

That method doesn't detect such browsers, which has the string Mozilla/4. and which are not MS IE, Opera or Netscape browsers. It is possible to detect all Mozilla between a certain range. The reasonable range could be browsers, which are newer than Mozilla/4.00 and older than Mozilla/5.0. The detection can be done by using function floatval(), which converts string into decimal values (they are called also as double):

$Moz4All = ((floatval(substr(stristr($userBrowser, "Mozilla"),8, 3)) > 4.0) && (floatval(substr(stristr($userBrowser, "Mozilla"),8, 3)) < 5.0)); /* The first value of the substr() function determines after how characters the sub-string starts and latter defines the length of the sub-string. If in the end of the searched string would be empty space or character they are not harmful because that possibility has been taken account. It is not necessary to check the value by using the ctype_digit() function. According to an e-email when using the float data type it is important to check that the data type real is float. It is also possible to split comparative floats with the explode()-function from the points, where are commas and then compare separately values before and after commas by using the intval() function. */

Server-specific notes:

  1. All servers don't support the floatval() function because it is supported starting from PHP 4.2.0 but the functionality can be get in older versions of PHP by a user-defined function.

    php.net: floatval

In some cases the needed conversion function is intval() (for example (intval(substr(stristr($userBrowser, "Gecko"),6, 8)) for Gecko/20001108). My browser detections don't take account all browsers but most however. It is also worth to note that some browsers user either the rendering engine of MS IE or Mozilla Gecko browsers. Those browsers have been taken account among MS IE and Gecko detections. On browser, which is worth to mention is Konqueror, which is available in Linux platform and Safari in the Mac platform. It it easy to take account it at the same way as other browsers. Below is a detection string of Safari:

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/48 (like Gecko) Safari/48

By using JavaScript-detections could be asked if (document.layers), which is only supported in the Netscape 4.x series browsers. The problem is however that it not possible to make detections using variables (for example var 4NN4 = (...);) and it is necessary especially way to take account Netscape 4.x. In my mind JavaScript-based detection works in that mean worse than PHP-detections.

The another remarkable area is unknown DOM-browsers. By using JavaScript-detections it is possible to ask if (document.getElementById) and UA string are not needed at all. It is not any reason to try to know all browsers, which support DOM. If for example all DOM-capable browsers needs certain CSS I would use the following system:

  1. The author defines common CSS for all such browsers, which support DOM and the proprietary DHTML of MS IE.
  2. That CSS has been defined so that Netscape 4.x doesn't read it. In my mind the easiest way it to generate comments around such CSS-files, which are not intended for Netscape 4.x series:
    <?php
    include('...');
    /* That file defines variables. */
    if ($NN4){echo "<!--\n";}?>

    <link rel="stylesheet" ...
    ...

    <?php if ($NN4){echo "-->\n";}?>
  3. Browser-specific additional files has been get by PHP (a model[S] and related variable definitions[S]).

It is possible to combine JavaScript and PHP detections. First as far as possible with PHP and for browsers, which PHP-detections don't fit PHP will generate necessary JavaScript or a reference to a JavaScript file:

...
else {
echo "<script language=\"JavaScript\" type=\"text/javascript\" src=\"../Navigoinnit/AdviceBrowserSpecificCSS.js\"></script>"; }

In addition of ordinary (X)HTML-browsers thema are also browser of cellular phones in order to read WML-pages. WML 1.x resembles so much XHTML that with relative small modifications it is possible to create from the same material different versions for both WML 1.x and (X)HTML capable browser.

Compared WML 1.x with HTML WML has few elements. In this solution has been used elements, which WML 1.x capable browsers don't identify but they should not be harmful for them. WML has also special elements and attributes, which don't belong to XHTML. Following elements are common (I have also a table[S] of WML 1.2 elements):

If WML-browsers are intended to support at least following matters should be taken account:

Instead of ordinary browser detections WML-browsers could in principle detect by detecting which mime-types, which tells which file formats browsers directly (without plug-ins) support. Used variables are either $_SERVER['HTTP_ACCEPT'] or $HTTP_SERVER_VARS['HTTP_ACCEPT'] (the latter must be used if global variables are not allowed). Below is a test, which tells if your browser informs enough supported mime-types. It also list what mime-types yuor browser informs (below is the test code):

Your browser tells enough supported mime-types to the server!

Your browser tells following mime-types to the server:
text/html
application/xhtml+xml
application/xml;q=0.9
*/*;q=0.8
<?php
$MimeTypes = $HTTP_SERVER_VARS['HTTP_ACCEPT'];

if (stristr($MimeTypes, "application/xhtml+xml") || stristr($MimeTypes, "text/html"))
{print "...";}

else {print "...";}

print "...";

$aMimeTypes = explode(",",$_SERVER['HTTP_ACCEPT']);

for($i=0;$i<count($aMimeTypes);$i++){
echo $aMimeTypes[$i] . "<br />";
?>

The test succeeded well enough with an Opera and a Gecko browser, but not with MS IE 5.5. The system could work, if all WML-browsers inform that they support WML and in the first condition has been asked stristr($MimeTypes, "wml". If all WML-browsers don't do that, it is necessary to find some other detection method.

phpfreaks: Mime Types.

The alternative of the modularization, which I have proposed is heavy XSLT-transformation, where document have fist been created as XML-documents, which then have been transformed either WML 1.x or XHTML documents.

New cellular browsers support WML 2.0, which base on XHTML. For those browser the optimal solution could base on simplified XHTML-documents. In order to take account them it might be necessary to create different navigation and structure modules of Web-pages.

[Top]

Conclusions

Creating as dynamic documents as possible by using PHP and CSS for various platforms I recommend to take account following principles:

[Top]