Document:

Xampp Programing Tutorial

TOP

HTML lite
Paragraphs
CSS
Positioning
Lists
Tables
Div/Span
Characters
Fonts
Images
Hot Links

Xampp
HTML Heavy
Forms
Inputs
PHP
JavaScript.vl
DOM
MySQL
Program
JavaScript.vh
Vanity

This first block of menu to the right is HTML and CSS appearance tags, or HTML Sans Forms

The second block of menu concerns data handling and retention, Forms and XAMPP Tutorial begins here...

HTML lite Basic syntax, tags, conventions and notation. Skip this part if you know anything about HTML.

Paragraphs (and white space) Why it doesn't do what you want. The reason multiple <p>'s doesn't get you more space between lines.

CSS Cascading Style Sheets. This is the preferred way to style text and other elements. You want to know how to do this, really.

Positioning How to put the element just so.

Lists Mostly useless, but yet another way to format text.

Tables A wildly overused way of putting elements where you want them. Try to avoid this.

Div/Span A better way of positioning than tables. This is what you do if you want your stuff to work on a mobi.

Characters Fun with characters and how to make < appear on the page.

Fonts And what has replaced them, really.

Images How to get and place them.

Hot Links With mustard! And other wild combinations.

Xampp X-platform Apache MySql Php Preprocessor Web Server, Database and C-like programming language all in one. You want to get this and make it your friend.

HTML Heavy Mostly forms and inputs, or "how do we get data back from the web page to the server.

FormsThis is a container for a bunch of inputs.

Inputs are containers for information from the user.

PHP This is like the language C, only not strongly (or at all) typed.

JavaScript.vl is not Java, but is useful none the less.

DOM Document Object Model. What the big kids are playing with.

MySQL This is long term memory for web pages (and anything else).

Program How to write programs with PHP

JavaScript.vh Yet more JavaScript.

Vanity In the end, all is ...

.

Rational:

The following is an HTML primer on the kinds of appearance HTML expressions (not forms or inputs). Don't be intimidated by the length of the material, there are lots of pictures and I do tend to ramble on. I've tried to write down everything useful I know about HTML and CSS. I hope you find it amusing.

HTML lite:

HTML is an acronym for HyperText Markup Language. It was born out of a need to format the presentation of text, images and data on screens of various and arbitrary sizes. A page of raw HTML can be thought of as having two types of information, text and formatting. Formatting appears between two angle brackets <formatting> and never literally appears on the rendered page. Formatting is used to control the appearance and placement of text and other objects on the page. Anything that isn't formatting is text and is on the page. Formatting can contain images, which also appear on the page and Hot Links which are clickable text pointing to other pages.

It is often interesting to look at the raw HTML when you see something amusing. Most browsers have a menu item that is something like View Source which allows you to look at the HTML directly. I am currently using Chrome as it provides a particularly sweet view of the tricks involved by right mousing over the item you wish to inspect and selecting Inspect Element. Firefox provides control-u as a quick way to get the entire page of HTML source and in Firefox 10 at least right mousing over an element will also allow you to Inspect Element. In Internet Explorer 10 bopping F12 brings up a suite of developer's tools. There is also the option to View Source under the right mouse button. I don't have ready access to other versions of IE.

Many internet forums and other types of software allow for the use of a subset of HTML 4.01 as well as plain text to get your point across. You can post text, images, hotlinks and video. Forms and anything inside forms like Inputs are right out. CSS (Cascading Style Sheets) are supported so the deprecated <font> is discouraged but will control the appearance of text.

Conventions: In general, anything that appears in bold between angle brackets as in <bold> is HTML and needs to be typed exactly including the angle brackets and any quote marks. If you see quoted text containing mumble it means this entire quoted bit is variable and you need to substitute the correct text for it.

Nearly all HTML tags (what we call the bits between the angle brackets) come in pairs. This makes sense as usually you want to do something, like make a chunk of text bold, and then not do it anymore. So we see a tag that opens the new formatting, some text, and then a closing tag. The closing tag generally looks like an opening tag with a forward slash in front of the text part, thusly: <tag>sample text</tag>. One exception to this is the paragraph <p> tag, which can be used on its own without a closing tag. Using a closing tag with <p> Your paragraph here </p> is considered good form though. The gods of HTML will smile on you if you do...

If you are posting images it is generally beneficial to place the image in a paragraph of its own and use a closing tag with <p> </p> as it helps the browser properly place images.

The tag-type is the first text after the left angle bracket that opens the tag. There must be no space between the angle bracket and the tag-type, if there is then HTML treats the whole business as text. There can be additional information in the opening tag that is not a part of the tag-type. This is shown as an attribute="value" pair following the tag-type separated by a space. The equal sign and the quotes are mandatory parts of the attribute/value pair. A common attribute is width="200" or height="15%". Distances on the screen can be specified as either pixels or as a percentage of the screen. Since the target screen is usually unknown percentages are the preferred style of dimension.

Anchors are tags which pin down a location. An anchor looks like <a name="sj29537_top">. This one is used to define the top of this page and is the first line in the raw HTML that renders into it. The tag-type is the a after the left angle bracket, the name="sj29537_top" is an attribute/value pair which serves as an identifier for this particular anchor so that it can be referred to by other bits of HTML. A closing tag would be nice, but it isn't required for this anchor. The current preferred form is <a name="sj29537_top" /> with the closing explicit in the opening tag. Adjacent to the major headings on this page there is another anchor <a href="#sj29537_top">top</a> which is also a hotlink. This does have a closing tag, which serves to delimit the text that is to be the clickable hotlink. The # in front of "sj29537_top" in the href tells the software that the anchor referred to is located on the current page. This is not optional. The second top is text which is being formatted into a hotlink by the HTML that surrounds it.

Another thing that it is good to know is how to nest (order so as to do what you want) the tag pairs. These examples:
<tag_A> some text </tag_A> or
<tag_A><tag_B> some text </tag_B></tag_A> or
<tag_A> some text <tag_B> some more text </tag_B> even more text </tag_A>
are all legal and useful nestings.

<tag_A><tag_B> some text </tag_A></tag_B>
and similar broken orderings are not legal or useful. In general, the rule is that you can not close a tag with an open tag inside. Most browsers will handle this gracefully and close all of the open tags inside the one being closed, but you won't see the behavior that you desire.

Paragraphs & White-space:

HTML eats excess white-space. If you type two or more spaces in a row between words HTML will reduce all of the spaces and tabs to a single space or tab. Carriage Returns (the Enter key) won't do you any good either. Without special care it is easy to end up with a wall of unreadable text. It's quite cruel. If you want white-space beyond a single space you need to insert it explicitly by typing <br> or <p> for a CRLF and a paragraph, respectively.

Break <br> works like you expect Enter (or Carriage Return) to work. It gets you a single LFCR (Line Feed Carriage Return, just like an ancient typewriter). Two styles of break are in use, the preferred version (used in HTML 5) <br /> which contains its own closing tag. Paragraph <p> makes what follows into a paragraph set off by linefeeds. Neither <p> or <br> requires closing tag. The browser software will assume a paragraph is closed when it encounters the next <p>. Closing a paragraph actually makes good sense, closing a break seems like a waste of perfectly good characters.modulo the HTML gods referenced above.

Blockquotes are another useful trick. This entire paragraph has been enclosed in blockquotes. Anything you put between <blockquote> the example text <blockquote> gets indented and set off by linefeeds before and after. This example, rendered, will look like
the example text
the text above. Blockquotes can be nested (placed one inside another) and are a great way to distinguish the source of a quote from your own text.

Preformatted, or the <pre> tag provides a way to grab a bunch of text that is already formatted with tabs and spaces and not have HTML eat all that lovely white-space. As usual a closing tag is required with this </pre>. You can use this trick on a webpage but you need to realize that if the text you are copying wraps because it runs into the edge of the page and not because there is a CRLF present it will behave the same way in the preformatted chunk.


Horizontal Rule <hr> generates a horizontal line the width of the page. People often use this to separate their comments from those being commented upon. This also does not need a closing tag. A width can be set with this element, <hr width="150"> looks like:


Note that it is automagically centered. You can align="right" or "left" to position it explicitly. The usual caveat about using percentages instead of pixels applies so the preferred form looks like:
<hr width=10% align=left>
Which yields:
<hr style="width:50%;float:right;">


This horizontal rule uses CSS style to set the attributes. Notice that you can specify the width in either pixels or as a percentage of the available screen. With the proliferation of device screen sizes the latter method is preferred. Float is pretty interesting in that it allows the text to wrap around the floating object rather than insulating it in its own pseudo-paragraph.

CSS: Cascading Style Sheets

HTML mostly grew by accretion. Sure, there was a standards committee which set lots of standards (that's why we have so many); but the reality is that HTML evolved in the rough and tumble of the marketplace, and it shows. Various browser companies tried to distinguish themselves in the market by offering to "embrace and extend" the standard so as to fracture it to near un-usability. Lots of the code that services browsers checks to see which Version of IE is running so they know to rub their belly clockwise instead of counter-clockwise while standing on their heads. Then there is the whole disaster that is Flash, the delivery vehicle of choice for video.

To bring order from chaos it was decided on high that a new standard was needed. This is HTML 5. Currently HTML 4.01 is in broad use. There is a transition plan, of sorts. I suspect that, like Fortran and DOS, HTML 4.01 will never really die and the code written in it will always run in its own charmingly crippled fashion. But we can do better.

As a markup language HTML allows nearly infinite fiddling with page layout in great and fine detail. What it fails at is making any attempt at constructing a common theme or appearance for a collection of pages not be much more work than it is worth. It is this failing that CSS (Cascading Style Sheets) addresses.

HTML scatters appearance information throughout the document in <font size='3' color='red' face='ariel'> lots of fiddly bits. This is fundamentally wrong in that the information contained in the document is very distinct from the document's appearance. It is very easy to imagine the same document information in a variety of different appearances depending on the context. CSS solves this problem by moving all of the appearance information to one (or a few, it does cascade) place(s).

There is a starting place for all of this cascading. It's variable, but most folks start with a Style Sheet. It the case of this program it is located at ~/include/style/style.css This file is human readable text that describes the default appearance of the document it describes. This file is included as part of the <head>. What included means is that the contents of the file are inserted in that place. The head of an HTML document is non-printing (or rendering, it's only bits) as opposed to the body which is rendered (shown, painted on the screen). The head is where we put the bits of the document we don't want the reader to see. This includes information about the document itself (called meta-data), scripts that run when the user dinks with a control, and the appearance directives contained in the style.css file.

To make things a bit more concrete lets look at tables. Tables are wildly overused in HTML to position things relative to other things. The default appearance for a table is to have no border. Just for the sake of this illustration assume that the default for tables was a black border 1 pixel wide. Before CSS it was necessary to specifically turn on that border on each and every table in the document. This document makes extensive use of tables and the vast majority of them do not have borders. It would be nice if we could just turn them all off by default. Here's how it's done:

  <style>
    table,td,th
    {
    border:0px solid cyan;
    }
  </style>
This little fragment of style.css sets the default border for all tables in the document to be 0 pixels wide (which doesn't render), a solid as opposed to a dashed line, and colored cyan. While this is part of my file, style.css, you could just as easily drop that bit of code intact into the body of a document and it would work. Because it is between <style></style> tags the text describing what we want to do to tables is not rendered. The message is that you can use CSS anywhere, not just in the style.css file. Now, the default is that all table borders are turned off and for the few that I want to turn on I can do that locally by typing something like:
<table style="border:4px solid black;padding:15px;">
Which makes a table (much deleted detail) with a solid black border 4 pixels wide. The padding refers to an interior spacing within the table. CSS lets you set document wide defaults which are easily over-ridden locally at need. The closest CSS directive to an object controls its appearance. This is how styles cascade.

The syntax of CSS is a bit different than vanilla HTML. This is intentional so that the browsers can tell the difference so they know what to ignore, but it is also an improvement. HTML uses value="attribute" pairs to specify things. The CSS style is property:value; The semi-colon is required to delimit the end of the value(s) as property_0:value1 value2 value3;property_1:value1; is syntactically correct. A property and its associated values are referred to as a declaration.

Declarations are usually attached to a selector in style.css files. In the fragment above the selector(s) are table,td,th. This is what you hang the declaration on. As we have also seen above, declarations can appear in-line, as in

<table style="border:4px solid black;padding:15px;">
Notice that while we are using CSS to specify the behavior of the table we still have an HTML value="attribute" pair which contains the CSS declarations. Since we are mostly using CSS in-line you will see style="declaration(s)" rather often.

I find that when debugging layout problems (too many tables) it is helpful to turn on the borders of tables so you can see where they are. CSS makes this easy. Another tip is that if you highlight all of your page (control-a, Select All) you can also easily see the table borders.

This document was originally written in an HTML 4.01 centric fashion. I am now trying to use CSS exclusively because it is so much better. Information will be provided on both styles, but CSS is preferred and it rules when used. What is meant by this is that if CSS is in use for defining table borders using HTML 4.01 appearance directives like:

<table border="2" color="red"> 
will just fail without notification.

Positioning:

Screen Sizes

With the proliferation of display devices, screens now come in a wide variety of sizes and aspect ratios. The image below illustrates the range of screens possible. Differing aspect ratios are shown on the diagonal lines with the ratio in circles towards the lower right.

Given the wide variation in screen resolution and size when we step from mobi to fondleslab to display to HDTV it is lunacy to specify screen position in term of pixels. There is no way to know what sized screen you are imaging to so it is best to reference screen sizes and positions in percentages instead. The resulting size is the percentage of the width (or height) of the enclosing container. This is most useful when specifying positions and sizes of tables and images. The HTML for the image above looks like:

<img src="http://upload.wikimedia.org/wikipedia/commons/4/44/Vector_Video_Standards5.svg" width="95%">

The width="95%" part sets the image width to 95% of the width of the enclosing container. We leave the height unspecified so that the computer will figure out the correct value so as not to distort the image. If you wish to distort the image you may specify a height as well.

Things that are text related, such as the whitespace around a paragraph or header and text sizes are best specified in em. One em was originally the width of an M in the current font. In a multi-lingual world where not all alphabets have an M in them, the meaning has evolved to mean the height of the current font. As the user changes the magnification on a page the size of an em changes with it. This produces a pleasing scaled effect to the eye not possible when spacing objects in pixels.

Other unit values available are in inch, cm centimeter, mm millimeter, ex x-height of a font (x-height is usually about half the font-size), pt point - 1/72 of an inch, pc pica - 12 points and px pixels - a single dot on the screen. If no units are specified pixels are used by default. Best results across the broad spectrum of displays are achieved by exclusively using em and percent to specify size and distance. Try not to do anything else.

HTML 4.01

Any element (anything between tags) can be explicitly positioned by either putting it in a table or centering it <center></center>. Beyond that, explicit positioning is purposefully made as difficult as possible so that you won't do it. Your page will be displayed on a variety of devices of differing sizes and the less you constrain where the elements are positioned the better the general result will be across the broad spectrum of displays.

Inside tables you can use the attribute <td align="right"> ("left|right|center|justify|char") are acceptable values. The "char" option is mishandled by all the major browsers so it doesn't see much use. Align can also be used with images and horizontal rule, <img src="http://mumble.com/image.jpg" align="right"> will work. So will <hr align="right"> This is all in the HTML 4.01 idiom that we are trying to make go away.

To summarize, using HTML you can Center an element or put it in a table to control its position. This is why tables are wildly overused.

CSS - The Box Model

The CSS model is a bit different. Each element on the page sits in a box, the properties of this box determine where the element appears in relation to other elements. The Margin is completely transparent and is used to clear an area around the element. The Border has an associated color and width but can also be made transparent. Padding is the space between the content and the border and it has an associated background color. Finally, at the center is the element itself.

From the outside in:

Margin
A margin declaration looks like
margin:auto|length|%|inherit 
The symbol "|" should be read as "or". The property auto directs the browser to determine what is the best margin to use. The length property allows you to specify an absolute length for the margin. Likewise, % allows you to specify the margin as a percentage of the container of the element. Inherit means to inherit the margin settings of the container of this element.

Margins can be individually called out like

margin-top:100px;margin-bottom:100px;margin-right:50px;margin-left:50px; 
. All four margins can be specified in a single declaration by remembering that the order of specification starts from the top and rotates clockwise. The declaration
margin:10px 20px 30px 40px; 
specifies that the margins be top=10 right=20 bottom=30 and left=40 px.

The margin property can have from 1 to 4 values. If you use one value it is the margin for all four sides. If you use 2 values, the first value is for the top and bottom and the second value is left and right. Three values means that the first value is the top margin, the second value is left and right margin and the third value is the bottom margin.

Border
The shorthand border declaration looks like

border:2px dotted black; 
This is, in order the width, style and color. The first border property of interest is border-style: If border-style: isn't set to something (like border-style:none;) then none of the other border properties are applied. This makes perfect sense, if you don't have a border to style, why bother.

Like margins, borders can be individually set with border-top:1%;border-right:2px;border-bottom:1em;border-left:2px; Colors can be set with border-color:red; or individually with border-right-color:green;

Here are examples of the 8 available border styles.

  <table style="border:0px none black;padding:0px;margin:1em 2em;"><tr>
    <td style="width:100px;text-align:center;border:4px dotted black;">dotted</td>
    <td style="width:100px;text-align:center;border:4px dashed black;">dashed</td>
    <td style="width:100px;text-align:center;border:4px solid black;">solid</td>
    <td style="width:100px;text-align:center;border:4px double black;">double</td>
  </tr></table>
Yields:
dotted dashed solid double
The border on double needs to be at least 4 pixels wide to show up as anything but solid. The size of the dots, dashes and spaces between them are scaled to the width of the border.
  <table style="border:0px none black;padding:0px;margin:1em 2em;"><tr>
    <td style="width:100px;text-align:center;border:6px groove aquamarine ;">groove</td>
    <td style="width:100px;text-align:center;border:6px inset aquamarine;">inset</td>
    <td style="width:100px;text-align:center;border:6px outset aquamarine;">outset</td>
    <td style="width:100px;text-align:center;border:6px ridge aquamarine;">ridge</td>
  </tr></table>
Yields:
groove inset outset ridge
With these border styles lighter colors seem to work better than darker colors.
<table style="border:0px none black;padding:0px;margin:1em 2em;"><tr>
<td style="width:300px;text-align:center;border-width:6px;border-color:aquamarine;
  border-style:groove inset outset ridge;">
    mixed - groove inset outset ridge</td>
</tr></table>
Yields:
mixed - groove inset outset ridge
This last bit mixes all four border styles. The real power of this is that it doesn't just work with tables, which already have a border defined in HTML anyway. It also works with elements that don't have a border, like paragraphs.
<p style="border-width:15px;border-color:LightGreen;border-style:groove inset outset ridge;padding:1em;">
 a bunch of text </p>
Yields:

Which allows and enables you to do stupid stuff like this. Try not to get carried away. This is a paragraph and not a table so it gets treated like text, except for the presence of the box. Previously if you wanted a border on something you had to put it in a table. Now, you can put a border on any element. This paragraph and the box around it resize if you change the width of your browser, the tables don't unless their size is specified as a percentage of the width of the enclosing container. Notice that we are using 1em as a padding to keep the text from running right into the border. If we use em instead of pixels, the border will be about 1 character's worth of space no matter how the user sizes the text.

Padding
Padding is the space between the actual element itself and its border. Padding takes on the background-color of the element. Like margins, padding can be individually called out like:

padding-top:1em;padding-bottom:1em;padding-right:3em;padding-left:2em;
. All four paddings can be specified in a single declaration by remembering that the order of specification starts from the top and rotates clockwise. The declaration
padding:10px 20px 30px 40px;
specifies that the padding be top=10 right=20 bottom=30 and left=40 px.

Like margin, the shorthand version of padding can have 1 to 4 values with their effects exactly like the margin shorthand described above.

CSS - Positioning

CSS refers to the normal positioning of HTML on the page as static positioning. This is the default behavior if other positioning is not specified. Elements are placed on the page in order, from left to right till the margin is reached then down the page for the next line of flow, compressing whitespace as much as possible. This is what happens with no tables or other attempts at specifying position.

Fixed positioning allows you to cause an element to remain in place in the browser window no matter how the window is scrolled or sized. The hotlink at the top right of this page is an example of fixed positioning. It is always available to take you to the top of the page.

Relative positioning allows you to place an element offset from where it would normally be in its static position. It's like a nudge, a fine tuning of a position the element intends to take anyway.

Absolute positioning allows you to place an element anywhere on the page but moves with the page. The element is taken out of the flow of other elements which allows for stacking elements in the same position using this method.

Float is one very useful method of horizontal positioning. Without CSS, the only way to get a control on the right side of the page was to use a table and align="right" that element inside the table. Float directs an element to move to the right rather than packing to the left as in static positioning. Judicious use of float should eliminate the need for tables to place controls and anything else.

<p style="float:right;margin:0px;padding:0px;color:red;">This should float right.</p>

This should float right.

And this is the next, non-floating paragraph. Notice how the text of this paragraph flows around the floated one. It's best to think of the floated element as being dropped into place and then anything in the normal flow just flows around it. Margin and padding are reduced to zero to make the text flow nicely, without the change that floaty bit has the same margins and padding as a normal paragraph, and it shows.

  

Lists:

Lists are another way to order chunks of text and white-space. Lists can be either ordered, with numbers or letters preceding the list items or unordered with selected dingbats (disc, circle, square) fronting the text. The default dingbat is a disk; losing the dingbats is unfortunately not an option unless you are using CSS. An unordered list looks like:

<ul>
  <li>Coffee</li>
  <li type="circle">Tea</li>
  <li type="square">Milk</li>
</ul>
which yields:
  • Coffee
  • Tea
  • Milk

Ordered lists are a only marginally more interesting. A number of numbering schemes are available. Here I have abused them as much as possible.

  1. Coffee
  2. Tea
  3. Earl Grey
  4. Oolong
  5. Milk
  6. Whole
  7. Skim
  8. Condensed
  9. Powdered

Tables:

The Fool is always greater
than The Proof.
<table style="width:30em;border:4px solid green;padding:1em;" >
  <tr>
    <td><center><font color="blue" face="arial" size="5">The Fool is always greater<br />
     than The Proof.</font></center></td>
  </tr>
</table>

This is what used to be done to get a border around some text. Notice that we used CSS to specify the table border. This is necessary because I use CSS to globally control the appearance of tables. Using the deprecated table attributes border="value" will not work in this system. The deprecated <font> will still continue to work, as above, for as long as the browsers support it. Here is how to do the same thing in a simpler fashion with CSS:

<p style="width:17.5em;border:4px solid green;padding:1em;text-align:center;color:blue;font:1.5em arial,sans-serif;">
The Fool is always greater<br />than The Proof.</p>

The Fool is always greater
than The Proof.

Notice that the width of the top table is 30em and the bottom paragraph is 17.5em. This is because the default font changed from size=5 to 1.5em.

A 3 x 3 table of images:

Who dat?
<table>
  <tr>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisa.jpg" style="width:100%"></td>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisa20apc1.jpg" style="width:100%"></td>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/Raptor_Mona_Lisa_by_Xfreakdom.jpg" style="width:100%"></td>
  </tr>
  <tr>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisajudge.jpg" style="width:100%"></td>
    <td><center>Who dat?</center></td>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/art_class_mona_lisa_by_courtelle_k-d3a7ins.jpg" style="width:100%"></td>
  </tr>
  <tr>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisarobocop.jpg" style="width:100%"></td>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisamolly.jpg" style="width:100%"></td>
    <td><img src="http://enemiesforeignanddomestic.com//sj/images/monalisamatrix.jpg" style="width:100%"></td>
  </tr>
</table>

Tables are yet another means of generating white-space. Tables are used pretty broadly to control the placement of objects on the page. Any object can be placed in a table, images are shown above and text below but you can just as easily place any element in the table data. Without some method of placing objects explicitly HTML puts them where they use the least space on the screen. Tables allow you to fairly rigidly control where objects are placed relative to each other.

Month Food Fuel Rent
January $104 $123 $500
February $93 $112 $500
<table style="border:1px solid black;width:30%;">
  <tr>
    <th>Month</th>
    <th>Food</th>
    <th>Fuel</th>
    <th>Rent</th>
  </tr>
  <tr>
    <td>January</td>
    <td style="border:1px solid black;">$104</td>
    <td style="border:1px solid black;">$123</td>
    <td style="border:1px solid black;">$500</td>
  </tr>
  <tr>
    <td>February</td>
    <td style="border:1px solid black;">$93</td>
    <td style="border:1px solid black;">$112</td>
    <td style="border:1px solid black;">$500</td>
  </tr>
</table>

The opening tag <table style="border:1px solid black;"> has an attribute CSS style "border" which defines the width of the border around all the table entries. The default is zero, yielding no border. This is set by the global CSS which gets over-ridden locally by the style="mumble" attribute Note that there are two sets of borders, the one associated with the table as a whole, and a border for each of the individual table header and data entries. These are individually settable by including a style="border:1px solid black;" attribute value in the opening tag of the table data or table header.

The first row is found between the first table row tags <tr> </tr> This row is special in that it contains headers and not table data and this is indicated by the <th> Value </th> tags with the value of the header between them. Headers need to be explicitly called out so that programs which sweep these files know where the data is and where the labels for the data are.

The subsequent rows are table data, indicated by the <td> Value </td> tag pair. Note that all of the opening tags have closing tags. The table ends with </table>

You can make tables with multiple rows in a particular column, vary columns by row and combine images, text and anchors as table elements. The following example shows all of that.

Freedom ≠ Free Stuff☭
I, for one, welcome our new Cybernetic Overlords /.
Mash Dobbshead® for HTML, bop Hello_Cthlhu for XAMPP
<table style="width:30%;border:1px solid black;">
  <tr>
    <td style="width:5%;border:1px solid black;" rowspan="2">
      <a href="http://enemiesforeignanddomestic.com/sj/index.php#html" target="o">
      <img src="http://enemiesforeignanddomestic.com/sj/images/bob_dobbs_color.gif" width="100%"></a>
    </td>
    <td style="width:30%;text-align:center;border:1px solid black;" >
      Freedom ≠ Free Stuff☭
    </td>
    <td style="width:8%;border:1px solid black;" rowspan="2">
      <a href="http://enemiesforeignanddomestic.com/sj/index.php#xampp" target="o">
      <img src="http://enemiesforeignanddomestic.com/sj/images/hello-cthulhu.gif"  width="100%"></a>
    </td></tr>
    <tr><td style="width:30%;text-align:center;border:1px solid black;" >
      I, for one, welcome our new Cybernetic Overlords 
      <a href="http://slashdot.org/" target="o"> 
      <b><font color="teal">/.</font></b></a>
    </td>
  </tr>
  <tr>
    <td colspan="3"><center><span style="font-size:0.8em;">
      Mash Dobbshead<sup>&reg;</sup> for HTML, bop Hello_Cthlhu for XAMPP
    </span></center></td>
  </tr>
</table>

Backgrounds:

http://enemiesforeignanddomestic.com/sj/images/th_champagn.jpg
http://enemiesforeignanddomestic.com/sj/images/Verdicch_wall.jpg
http://enemiesforeignanddomestic.com/sj/images/aquamauvecirclebg.jpg
http://enemiesforeignanddomestic.com/sj/images/aquaturquoisbg.jpg
http://enemiesforeignanddomestic.com/sj/images/aquasolidtexturebg.jpg
http://enemiesforeignanddomestic.com/sj/images/american_flag.jpg
The backgrounds above are a small sample of the images that are available around the web. Any image can be used as a background.

A table with a moving .gif and backgrounds.


<table background="http://enemiesforeignanddomestic.com/sj/images/Verdicch_wall.jpg" cellpadding="20">
  <tbody><tr><td>
    <table bgcolor="#c0c0f0" cellpadding="30">
      <tbody><tr><td>
        <table background="http://enemiesforeignanddomestic.com/sj/images/american_flag.jpg" cellpadding="40">
          <tbody><tr><td>
            <img src="http://enemiesforeignanddomestic.com/sj/images/gadsdenanimated_revised.gif">
          </td></tr></tbody>
        </table>
      </td></tr></tbody>
    </table>
	</td></tr></tbody>
</table>

This is three tables, each inside another with an image at the center. We are not using CSS for this example just to show how it is done with HTML. We are not using table borders (which the global CSS has turned off) so there isn't a problem. One of the tables uses bgcolor=, the other two use image background= to set the backgrounds. Borders are all set to zero by CSS. The similar table below has borders set to outset and inset, and that code follows the table. We used CSS for this table. These borders are kind of cool in that they look like they are lit from above and to the left giving the table a kind of 3-D look.

<table style="background-image:url('http://enemiesforeignanddomestic.com/sj/images/blueribbon349.jpg');border:30px outset grey;padding:40px;">
  <tbody><tr><td>
    <table style="background:url('http://enemiesforeignanddomestic.com/sj/images/th_champagn.jpg');border:10px inset grey;padding:20px;">
      <tbody><tr><td>
        <img align="middle" src="http://enemiesforeignanddomestic.com/sj/images/bluelk.jpg" width="350px" height="234px">
      </td></tr></tbody>
    </table>
  </td></tr></tbody>
</table>

Div & Span:

People used to make extensive use of tables to control placement of objects on a page. This has fallen out of favor among the cool kids with the proliferation of different sized screens. Rigid fixed tables that look good on a full sized computer screen are totally unmanageable on a smart-phone or fondle-slab. It was really quite dreary and something had to be done so <div> and <span> were invented.

Div and Span are used to mark out sections of the document for various sorts of manipulation. Div puts a line break before and after the div, span does not but this can be changed with CSS. That is pretty much the difference between the two. By using an id attribute like <span id="mumble_id"> Target </span> a target for javascript can be created in the document. You might want a counter, or a timer to show up on the screen that you have created with javascript running in the user's browser. Those annoying floaty things that show up after a time on some websites use this technique. Unique id's are readable by javaScript using the DOM. <span id="time2"> Target </span> Target creates a target for the javaScript that keeps track of the time that is started when the body of the document loads.

Format can be locally manipulated with CSS using div/span. <div style="color:blue;"> Bluish paragraph thing. </div> works like a charm.

Characters:

Quick things you can do with characters are bold and italic. You get bold with <b> bold stuff </b> which looks like bold stuff. Italic works the same way with a different letter: <i> italic stuff </i> gets you italic stuff. Other things you can do are <del> delete stuff </del> delete stuff, which replaces the deprecated <strike>. There is an underline tag as well that should not be used as it confuses people who think it is a link.

There is also a <big> bigger stuff </big> which yields bigger stuff and <small> smaller stuff </small> which rolls like smaller stuff. You can get your readers to really squint at your stuff by <small><small> really small stuff </small></small> really small stuff. If you are a fan of the typewriter there is also a <tt> typewritten stuff </tt> and it types out typewritten stuff as expected.

Superscripts and subscripts are also available. He<sup>3</sup> gets He3 H<sub>2</sub>O makes H2O

There are some characters that are special in HTML, like the left and right angle brackets <> and a few others. Obviously there has to be a way to render those characters on a page. This is done with another pair of special characters, the ampersand and semicolon ( & ; ). These are used as delimiters for either a numeric value or a short and specific reference to the character desired. See http://www.w3schools.com/html/html_entities.asp for a more complete treatment.

Another means of generating white-space is non-breaking spaces, &nbsp; This creates a space that HTML won't eat. You can put multiple of these in a row for spacing but it is considered poor form. Mostly because the spacing depends on the current font and if it is a proportional rather than a fixed pitch font it gets even more complicated. Notice that the ampersand and the semicolon are used as delimiters (boundaries) for the value between them. A variation on this technique is how these delimiters appear on this page.

Fonts:

Fonts are deprecated since HTML 4.01 (the standards boffins are working on 5.0 now) CSS (Cascading Style Sheets) is the current preferred method for coloring and shaping text in HTML. Fonts may be used to manipulate text but CSS styles are preferred and should be used.

HTML 4.01

HTML lets you specify a font's face, color and size. The face is the font itself, arial, helvitica, and times are examples of font faces. Color and size are pretty obvious:
<font face="courier" color="red" size="5">Red Courier slightly Larger</font> 
Yields: Red Courier slightly Larger

What you can change about a font is its color, the typeface and the size.

Face is the typeface that you want the browser to render. Types available to most browsers include "arial" "times" "helvitica" and "sans-serif". You can specify multiple names with the preferred fonts first like this:

<font face="verdana,arial,sans-serif">

Color is the value contained in quotes after the color= part of the opening font tag above. Most normal names are supported, 147 total. For finer control hexadecimal values can be specified. For a full color treatment mash here.

Size is a numeric value between 1 and 7 inclusive with 7 being largest. Three is the default value and is used in the majority of this document.

CSS

Instead of face, CSS uses font-family: to specify face. An example of a bit of formatting that changes the face in the CSS style looks something like:
<span style="font-family:Times New Roman, Times, serif;">
This should be rendered as a Times or Serif font.</span>
Yields: This should be rendered as a Times or Serif font.

<span> is used to group elements together so that a style can be applied to them all without otherwise affecting the elements. Multiple font-family values are specified because what fonts are available is a function of the browser doing the rendering. If your browser doesn't have the fonts your specify it will use the ones it does have. For this reason it is best to use commonly available font-family values. A good list of what is currently commonly available can be found here.

Color is dealt with in much the same manner. Colors can be specified by name or numeric value.

<span style="font-family:Times New Roman, Times, serif;color:green;">
This should be rendered as a Times or Serif font.</span>
Yields: This should be rendered as a Times or Serif font.

Another CSS property of fonts is font-style:. This is used to generate italics or normal text. An "oblique" style is specified but poorly supported by existing browsers. Values available are font-style:normal; font-style:italic; and font-style:oblique;

<span style="font-family:Times New Roman, Times, serif;color:blue;font-style:italic;">
This should be rendered as a Times or Serif font.</span>
Yields: This should be rendered as a Times or Serif font.

To set the size of text something like font-size:16px is used. Size can be defined in a couple of ways. Sizes can be absolute. Size specified in pixels or em (1em is the current default text size, typically 16px; em is preferred because some versions of IE choke when asked to resize px).

<span style="font-family:Times New Roman, Times, serif;color:orange;font-style:italic;font-size:2.5em;">
This should be rendered as a Times or Serif font.</span>
Yields: This should be rendered as a Times or Serif font.

Size can also be specified as a percentage, as in font-size:100%. Using a combination of percentage and em produces consistent sized text across all the major browsers. To specify this in CSS use something like:

<style>
body {font-size:100%;}
h1 {font-size:2.5em;}
h2 {font-size:1.9em;}
p {font-size:1em;}
p.blue {font-size:1em;color:blue;}
</style>
in your style.css declarations. This will specify default sizes for body text, two headers and anything in two types of paragraph. One the normal color and the other blue. Use <p class="blue"> to get a blue paragraph. They should all resize smoothly and work as expected across browsers.

Two more font stylings are supported, variant and weight. Variant looks like font-variant:small-caps; the other value is "normal". What this does is substitute small capital letters for the lower case letters in your text. Font weight is like Bold with a finer level of control. It is used like so, font-weight:bold; or font-weight:normal; or font-weight:700; The numbers for weight go from 100 to 900 with 400 = normal and 700 = bold.

<span style="font-family:Georgia, serif;color:magenta;font-style:italic;font-size:2.5em;font-variant:small-caps;font-weight:100;">
This should be rendered as a Georgia or Serif font.</span>
Yields: This should be rendered as a Georgia or Serif font.
<span style="font-family:Ariel, sans-serif;color:magenta;font-style:italic;font-size:2.5em;font-variant:small-caps;font-weight:100;">
This should be rendered as a Ariel Slashed Zero font.</span>
Yields: This should be rendered as a Ariel Slashed Zero font.

Images:

<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png"><p>
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="30%">
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="15%">
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="7%">
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="4%">
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="2%">
<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="1%"> .
Yields:

.

J. R. "Bob" Dobbs receding into infinity...

<img src="http://mumble.com/image.jpg"> substitute the actual source of the image for http://mumble.com/image.jpg This image must be out on a server on the web someplace, not on your machine. This is why people have flickr and picassa accounts. You can easily find out the URL of an existing picture on the web by right-mousing over it and selecting Open Image In New Tab. This will open a tab on your browser containing only that image. The URL of that tab is the one to use as your src="" value.

Some of the photo storage sites on the web (flickr) try to drive web traffic to their site to harvest advertising by providing a convenient pointer to their site that isn't a URL to a .jpg To get the proper URL try right mousing over the image and select Open Image in New Tab. This should get you the naked image itself, without all of the surrounding advertising. This is the URL you want to use.

Access Denied! - No Hotlinking - Occasionally you will see an image that looks good on the site of origin but won't show up if you use it in a posting. Many sites block what they term as "hot-linking" thinking that people who link to their images from pages that are not theirs are stealing their hard paid for bandwidth. They have a point. Either use another image or host it on your own site to fix this problem.

Often the poster will see the image that hot-linking is not allowed for while other users are whining about no image present and red X's. This is because the poster's browser has cached the image and doesn't have to go to the blocked site to get it. A refresh of the page should show what is what.

Size: You can easily vary the size of a given image by specifying it. You may specify size in terms of pixels, em (one character height-width), or percent of enclosing container. Given the wide variation in display platforms the best results are usually obtained by using percent to specify size.

<img src="http://upload.wikimedia.org/wikipedia/en/a/a3/Bobdobbs.png" width="15%"> Yields:

If you are specifying the size of an image it is best to do it in only one dimension and let the computer figure out what the other dimension should be. This will result in images that have not been distorted. Another neat trick is to specify the image size as a percentage of the width of the container the image sits in. This results in a uniform presentation of the image across all possible platforms without having to compute the image size at all.

The native size of the J. R. "Bob" Dobbs picture above is 324x216 pixels. Typical screen pixels per inch numbers for normal displays are in the range of 75 to 150 so the original Dobbs'Head will likely appear on your screen somewhere between 2.88 to 1.44 inches wide.

The next row of Dobbs'Heads are scaled to the width of the enclosing container. We use the width because its value is mostly apparent on the screen. The value of the container's height is less so. The first Dobbs'Head is scaled to 30% of the width of the container. The next at about half that, and so forth... This produces a line of attractive Dobbs'Heads receding into infinity that occupies about half the width of your page, all without needing to know how wide your page is. The size of the images will change if you grab the edge of the page and make it wider or thinner. This is the reason you want to scale images (and anything else, really) by percentages rather than pixels.

In the past it was best to keep your scaling to powers of 2 to minimize scaling artifacts. Current smoothing algorithms and processor speeds make that pretty much unnecessary. Remember that scaling up will not introduce new detail into the existing picture.

Stationary images usually end with .jpg or some variation. Moving images are possible using images which end in .gif The .gif format allows for short sequences of stationary images to be presented like a very tiny movie. Another common format is .png which is a static image format from Microsoft. You will also see images that are .pdf Postscript Document Format. Images in .pdf format will often not post on websites because the .pdf file can easily be a virus container.

You can position an image relative to its surrounding elements by adding the attribute align="middle" to the tag. Recognized attribute values are top, bottom, middle, left and right.

<p><img src="http://enemiesforeignanddomestic.com//sj/images/61cb2_zQLMZ.gif" align="right" alt="Kittie doing its nails."></p> Yields:

This is some text to show how it flows around the image. This is before the image in the source HTML with a paragraph called out before the text. Isn't the expression of the cat's face just priceless? ♣

Kittie doing its nails.

And this is text right after the image. I have found left and right attributes to be useful, the rest not so much. You really seem to have to have quite a bit of text for the behavior of the flow to come out. Dinking with the browser width seems to help illuminate the behavior of the flow. Perhaps a smaller picture in the x-axis? But it's sooo cute.

Does adding a paragraph move the text down below the image? Nope, sure doesn't. Think of the anchor as the upper left corner of the image and as far as HTML is concerned that corner goes right after the club following "priceless", but it is aligned right so it starts on the line with the club ♣ and hangs to the right.

In general, if you are posting images it is beneficial to place the image in a paragraph of its own and use a closing tag with <p> </p> as it helps the browser software properly place images.

The alt="Kittie doing its nails." specifies the text that appears when you mouse over the image. Some folks use these descriptors by running them through vocal-synthesis software. The blind using computers find these descriptors quite helpful. It's important to remember that an image (as well as any other element) can be used as the clickable part of a hot-link.

Hot Links:

<a href="http://mumble.com/index.html"> Hot Text </a> Here, mumble.com points to the page you want to link, Hot Text is the stuff you want to be clickable. Hotlinks are another form of anchor which is appropriate since they too define a location.

Here is a hot link for a Google search on "furlongs per fortnight" that opens in a new tab. <a href="http://www.google.com/search?q=furlongs+per+fortnight&btnG=Search" target="o" title="Search furlongs per fortnight"><b><font color="#0039b6">G</font><font color="#c41200">o</font><font color="#f3c518">o</font><font color="#0039b6">g</font><font color="#30a72f">l</font><font color="#c41200">e</font></b></a> gets you this cute little mashable text:

G o o g l e

It's pretty and clickable. Let's look at the individual elements.

<a href="http://www.google.com/search?q=furlongs+per+fortnight&btnG=Search" target="o" title="Search furlongs per fortnight"> The first a is the anchor for this hotlink.

href="http://www.google.com/search?q=furlongs+per+fortnight&btnG=Search" target="o" title="Search furlongs per fortnight"> The href points to the Google search page with the search term following ?q= with the spaces replaced by +. The &btnG=Search part is a directive to the Google website to push the Search button. target="o" is the bit that makes it open in a new tab. title= sets the text that appears when you linger your mouse over the pretty letters.

This next bit prettifies the clickable text. It's pretty because of all of the <font color="#0039b6">G</font> manipulation. It's clickable because it lies between the opening tag for the hotlink and the closing </a> tag. You can make a hotlink out of anything this way. If you put an image between the anchors of the link clicking on the image will take you to the target page.

Text Copyright © 2011-2012 by Stephen Jackson, All rights reserved.

Xampp:

Xampp: Programming for the masses, C, MySQL, JavaScript & HTML together!

Or, learn to code the next Facebook™ in your spare time.

The story is that Facebook™ was initially written using this technology so that should give you some idea what is possible if you master this idiom. Admittedly, it doesn't scale to 800 million users, but it is pretty serviceable for most people and it's free.

Learning to program earns you power. Steadily all of the machines around us are morphing into computers surrounded by hardware that mediates the processor's interaction with the physical world. To change the behavior of any given machine all you need to do is change the software driving it. A remarkable number of machines are being built these days that explicitly include a function allowing a knowledgeable user to reprogram the device in total. Most of the routers for sale on the market today include this capability. You can buy a wireless router, which is essentially a linux box with a pretty good sized flash drive and a low power radio for ~$15. See www.dd-wrt.com for complete details.

But you don't need to master the intricacies of hardware to write the next Facebook™. After all, you are just shuffling bits around on existing hardware that you need to know really nothing about other than it can store and manipulate data in predictable ways. Pretty cool.

What follows is a tutorial on Xampp, a package that installs everything you need to build complex database driven websites. It is targeted at a person competent in HTML. By competent I mean able to use fonts, images and hot links. People who are not able to do those things may learn them by going to the top of this document for a tutorial on just those very things.

The first line of links at the top of the page is the FreeRepublic tutorial. The second line of links takes you to the Xampp tutorial, the one we will be doing here. The first one will be the installation of Xampp on your machine and serving up the world's simplest web page to your browser by a server on your machine. The tutorial is being copied to my FreeRepublic home page as it is being developed so if you want to read ahead it is available but it is a work in progress. The program that the tutorial will generate a skeleton of is complete and working very nicely, thank you. My task is leading you though the maze that is how one designs and implements such a thing to begin with.

What you make is up to you. Creation, especially under the current regime, is a revolutionary act. So get those Dewskies in the fridge and the coffee on the burner and let's code!

Xampp installation tutorial follows:

This is the beginning of a tutorial describing how to install software that will run a web server and a database on your personal machine. This will enable you to write and read web pages locally, without having to upload them to a server and these web pages will be able to read and write data to the database. You will also be able to program in C in a fairly convenient fashion, just by including it in the source.php file of the web page. The combination of persistent storage, programming in C and HTML & JavaScript as the user interface provides a convenient and free development platform for solving a rather wide range of problems.

The tutorial will proceed in a step by step fashion, using all of the elements described above. All of the actual code will be provided and each new piece will be explained along the way. It isn't my intent to provide an exhaustive reference to C, HTML, JavaScript or MySQL. Instead you will be pointed to those references when appropriate. I will try to explain each new thing as it occurs but if I miss one, feel free to rattle my cage.

Xampp is an acronym for X-platform, Apache, MySQL, PHP Preprocessor. You Windows people, don't run off; this works for you too. Xampp runs on Windows, Mac OS X, Linux and Solaris, sort of your full service package. It's a collection of programs that let you set up a database and a web server on your computer that enables you do interesting and useful things with data driven web-pages for free! Additionally, setting up an Apache server on your personal machine allows you to sharpen your HTML skills without a whole lot of unnecessary uploading to a server flap-doodle.

Why do this? Well, you can leverage your knowledge of HTML to configure a user interface which talks to a database which stores arbitrary information. Using PHP (which is a C preprocessor) you can do programming sorts of things inside webpages. For everyday manipulation and storage of data this works wonderfully. If it is your intention to do heavy math, say ray-tracing for optical design, well, there are probably better choices for programming that application. But for most purposes this technique is quite sufficient. If you are collecting a bunch of data and then pawing through it in a variety of ways and want to be able to do this from a variety of platforms in geographically disparate locations, well this is for you.

One of the beauty parts of programming this way is that the results are platform independent. You write the program once and it works anywhere that a web browser runs with any web browser. Given HTML 5 and Flash it is easy to incorporate video into your program as well, though for the life of me I haven't actually needed to do video yet. It's also a pretty neat way to learn C and Javascript which I will get into later.

The database we are using is MySQL. This is accessed by a preprocessor to the C programming language called PHP. PHP lets us embed C programs into web pages that run on the server side (which the user never sees) as opposed to scripts (like JavaScript) which runs on the user side and can be freely examined by the user. This is used to write web pages which are served up by a program called Apache2 which is a wildly popular web server. This collection of stuff is called Xampp. To get all of this juicy goodness go here:

http://www.apachefriends.org/en/xampp.html and select the correct installation for your operating system and follow the easy directions. If you are doing a windows installation select the installer option as opposed to the 7zip or winzip options. This allows you to do an uninstall. Accept the defaults and do not add MySQL and Apache as Services. This means that they will not start without you telling them to. This is something you might want to do later but for now let's start and stop these programs explicitly.

Under Windows, Xampp installs in its own directory at the root, c:\xampp. If you change this during the install to say, the more normal c:\Program Files\ things will work with XP but will break under Vista. I haven't checked with Windows 7. Don't do this, accept the defaults. You do need to determine and remember the document root directory for your installation. This is where you need to put the .html and .php files for the web server to find them. For all flavors of windows look for c:\xampp\htdocs, Linux users will find the document root at /var/www, Mac OS X and Solaris users should probably also find the root at /var/www but I don't know for sure.

Important Security Considerations:
Don't turn on your Apache server unless you are behind a hardware firewall. You should already be behind a hardware firewall. If you have a router between your computer and your ISP you probably already have a hardware firewall. Check, be sure. If you don't, Walmart had a sale last week on Cisco M-10 routers for $25 and you need one right now. I'm serious about this. If you turn on an unprotected server outside a firewall it will be infested by the Chinese within 24 hours. Most likely it will be infested in 2 hours but if I claimed that you probably wouldn't take me seriously; but there are people with Asian IP addresses trolling all the time. You need to block port 80 incoming, most routers do this by default. Port 80 is what your Apache server listens to on your installation. You don't want people outside your local net getting to your server, honest. These are shark infested waters, mate'e...better gear up.

After successfully installing Xampp you will be asked if you want to start the Xampp control panel. Answer yes and start the Apache and MySQL services on the control panel. This will take a few seconds to start. Then open Chrome or some other web browser and in the address bar type localhost and hit 'Enter' to navigate to the Xampp splash page. Select your language and you should see a page congratulating you on a successful install. In the navigation bar on the left towards the bottom you will see under Tools and selection for 'phpMyAdmin'. Remember that if Apache and PHP are not running none of the following works.

At this point you should have successfully installed a web server and a database on your local machine. This is kind of neat but you need some content, some web pages to look at for this to be interesting. This next bit describes the creation of a program that keeps a list of purchased items in a database and can more or less organize food and other consumables for a household. All of the elements described at the beginning of this section will be exercised and a vaguely useful program will emerge.

Now start phpMyAdmin to add a new user to the MySQL database access list. The User-Name needs to be 'admin' and the Password needs to be 'password'. These are both obvious values that really should be something else for security reasons. It is up to you to make that so if you desire. The only other place those values appear is in the 'include/connect.php' file and they may be freely edited to something more security conscious, but don't do that now. They need to be simple right now for the tutorial to work. Look along the top of the page for the tab 'Privileges' and select it. Then select 'Add New User' and a create a user 'admin' with a password 'password'. Both are all lower case and it does matter. The host setting is 'local' and check all of the global privileges and leave the resource allocations alone and 'Create User'.

<html>
  <head>
    <title>
	Minimal
    </title>
  </head>
  <body>
	Hello World...
  </body>
</html>
Locate your document root and copy the above code into a file there called "index.html" Under Linux the document root is /var/www and under Windows it's c:\xampp\htdocs. For historic and server population reasons we will refer to that directory in general, no matter what its actual name, as ~www. The ~ part indicates whatever path you have to take to get to your document root, the www is the actual directory name if your are using a sensible OS, otherwise substitute htdocs. It's a choice.

Type "localhost" (← exactly that, not your machine's name, no quotes) into the address bar of your browser and hit CR. You should now be looking at "Hello World..." Feel free to edit the <body> part to your heart's content. It's a way to prove to yourself that you actually are in control. Have fun.

Editing .html and .php files in Windows is best done with Programmer's Notepad. The reason is that PN knows about the syntax of .php (and many other languages) and will clue you up with colors when you have made errors in the placement of that single quote in a sea of text. For this sort of thing it's the bee's knees and you can find it at: Programmer's Notepad. Under Linux I am using Geany which offers a similar feature set to PN.

Recently I have started using Notepad++ which I think does a better job with mixed .html .php and javaScript files.

When you configured the MySQL db you created a user 'admin' with a password 'password' to allow the program to access the database. These names and passwords are rather obvious and will be easily guessed by any bored teenager. You can change this username and password by editing the file /include/connect.php and the appropriate user in phpMyAdmin to the values you desire. Don't do this now, they need to be exactly the current values for the tutorial to work. You will understand more concerning this later but you really need to remember about the bored teenager part, oh, and the Chinese.

HTML Heavy:

This is a more rigorous HTML section describing what you need to know to do stand alone web pages outside the Free Republic environment, perhaps on a server on your own machine using Xampp. HTML is an extension of XML (eXtensible Markup Language) which has been extended (hey!) to be especially useful in describing the appearance of pages. XML is designed to be both human and machine readable. All of the characters in an XML file are either markup or content. Markup begins and ends with angle brackets <markup>. Everything else is content. Some characters are special and sometimes need to be represented in a form that XML won't recognize (like <). There is a way to create these characters by representing them with with a code that begins with an ampersand and ends with a semicolon &char_desc;. The char_desc part is either numeric or a short alphabetic descriptor, like &amp; for & or &lt; and &gt; for < and >. Mash here for a more complete treatment.

A tag is markup which begins with < and ends with >. There must be no space between the < and the text which defines the type of tag, if there is XML treats the whole mess as text. Most tags are part of tag pairs which are individually referred to as start tags <tag> and end tags </tag>. There are also empty element tags like break <br /> which is its own start and end tag. Note that the forward slash / appears as the first character of the text part of the end tag and also as the last character of the empty element tag.

An element begins with a start tag and ends with an end tag. There may be content or other elements between the start and end tags. An element may also be an empty element tag, (honestly, I don't make this stuff up). Elements provide programs with well defined chunks of data that describe what they are about. As a bonus it is all human readable.

Web pages always begin and end with an <html> tag. Let's cut straight to the chase and show all the normal elements of an HTML page.

<html>
  <head>
    <title>
	Page title goes here...
    </title>
    <style>
	CSS Style, if you've got it...
    </style>
    <script>
	JavaScript here...
    </script>
  </head>
  <body>
	Hello New World...
  </body>
</html>

Make a subdirectory under your document root called "tutorial". If you cut and paste the code above into a file called "~www/tutorial/index.php" in the root directory of the Apache server created in the xampp section and point your browser at "http://localhost/tutorial/index.php" you should see "Hello New World..."

The exact location of root directory of the Apache server depends on the operating system that Xampp is installed on. We are using a subdirectory "tutorial" to keep all the files in one obvious place. The file name "index" is special to HTML. If we pointed our browser to "http://localhost/tutorial/" the server would look for the file "index.html" or "index.php" in the directory "~www/tutorial" if we didn't explicitly specify a file. We are using "index.php" which tells the server that the file should be run through the PHP preprocessor before being served up to the browser.

The only required bits are the opening and closing html tags <html></html> That is what makes an HTML page, a bit boring though. There are two main subdivisions of the page, the <head></head> and the <body></body>.

The <head> contains three elements, <title> <style> and <script>. None of the elements of the <head> appear on the web page proper, but you can see them by doing View Source with your browser. The Title is what appears in the tab at the top of the browser. The Style element contains CSS (Cascading Style Sheets) descriptions of the styles of various parts of the document. It is strongly recommended to learn and use CSS instead of the deprecated <font>. More about this later. The third section contains the Scripts. These are little bits of program that travel with the web page and do computation and interaction with the user in his browser. Scripts are powerful and interesting.

The <body> contains the web page content. This content can be as simple as text and images or it can be dynamically created by driving it with a database and a bit of clever programming.

Forms:

Most useful web pages collect data from the user and transform it in some interesting way. Forms are the method used to collect data from the user. Like everything else, a form is an element that looks like <form action="mumble.html" method="post"> some stuff in the middle </form>. That's all there is to it, just kidding. You can read more about forms here.

The action="mumble.html" part specifies what page will be presented back to the user when the data is entered and the Submit button is pressed. The data is entered into named Inputs which are contained in the form on the current page and that data is conveyed back to the server for use in creating the mumble.html page.

The method="post" bit describes how the information is passed back to the server when the submit button is pressed. If the method is "get" the information appears appended to the URL and is visible to the user. The preferred method is "post" because more information can be passed and it doesn't appear appended to the URL.

Because we are using PHP to construct our web pages, we can use a much more elegant construct for our forms that looks exactly like this:
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
This is much the same as the form above, except for the action part. This bit is a PHP script which runs on the server and just points to the current page in PHP-speak. You could just put the actual page name there but if you use this construct you can change the file name without having to edit the form. A self referring page allows you to write an interactive web page that looks like many pages but is really all the same page being called with different inputs. All of the following presumes this style of programming.

Replace the body part of "index.php" with the following:

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
	Hello World...
	<form>
  </body>
Now refresh the page and you should see no change, but you have added a form.

Inputs:

Inputs look like <input type="text" name="favorite_flavor" /> This is a type "text" which has a default size of 20 characters. Available types are text, button, checkbox, file, hidden, image, password, radio, reset and submit. The name="favorite_flavor" provides a "handle" or name for that particular input. Copy the text below and use it to replace the body of "index.php".

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
	Hello World...<br />
	Fave Flav:<input type="text" name="favorite_flavor" /> 
	<select onchange='updateMenu();' name='command'>
		<option value='Global Commands'>Global Commands</option>
		<option value='Add To List'>Add To List</option>
		<option value='Delete From List'>Delete From List</option>
	</select>
	<br />
	<input type="submit" name="submit" /> 
	</form>
  </body>

Save the file and mash reload on your browser and you should see:

If you see anything like the above you have a working form. There will be slight differences in size and fonts depending on what the defaults of your particular browser are, but it should look pretty much the same. Now, we are going to do a bit of debugging. What follows is probably my favorite PHP fragment.

<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}
?>
This is an embedded PHP Script. The first line is the opening token of the script, this alerts the PHP preprocessor that what follows until the closing bit (last line) is a PHP Script that should be processed. What it does is picks apart and prints out the names of all of the inputs passed back to the server along with their values. How it does this in detail is contained in the PHP Section but just accept it as a little bit of magic for the moment. Copy the above fragment and insert it in the file "index.php" immediately after the opening <form> tag.

Once you have done that and reloaded the page you can mash the submit button and whatever values you have in the inputs will be listed in text with the names of the inputs themselves. This saves a whole lot of heartache debugging web pages. You should see roughly the following above the select and text entry areas:

favorite_flavor=chocolate
command=Add To List
submit=Submit
Hello World...

You did type "chocolate" didn't you? To get to the interesting stuff we are going to have to understand more about PHP.

PHP:

Functions Variables Strings Concatenation If

PHP is a Scripting Language like JavaScript. Unlike JavaScript, which runs in the user's browser to mediate user interactions, PHP runs on the server in a fashion which is invisible to the user. It the user invokes View Source he won't see any of the PHP on the page. PHP is used to run C programs as part of the HTML pages on the server before the raw HTML is generated and presented to the user.

All scripts in HTML begin with <? Have script stuff here, and end with ?>. The default script type is JavaScript. To get the PHP interpreter you need to start the script with <?php You can find the PHP manual here. What you will find if you poke the link is a pretty good manual describing how the PHP preprocessor works and quite a bit of material about the language C. You need to know this, leave this tab open if you are not fluent in C.

C is fundamental. You can not go wrong learning C, it's everywhere you want to be. C in PHP is a little different than standard C, it is not really typed. This means that variables, which all start with $, can have any sort of value stuffed into them. If you try to multiply a character by an array this implementation will let you and not warn you. It's part of its charm. Let's talk about that magical little PHP fragment we are using for debugging:

<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}
?>
If your eyes glaze over as you read this next passage just skip it. I promised to do this bit earlier and understanding exactly how this works is not at all necessary to continue but it is a nice spot to stop and talk about the syntax of C as practiced by PHP.

The first line opens the PHP script. The second line assigns the value of "true" to the variable $debug. The assignment operator is an equals sign = . Note that the line, and what we call the expression ends with the semicolon → ; ←. Expressions are bits of C that have meaning and are almost always terminated with a semicolon. Expressions may continue across lines that don't end with a semicolon.

The third line is an if statement, if $debug is true (and it is, we set it the line before) then we do all of the stuff inside the first pair of curly braces {...do all this stuff...}. This is the entire rest of the line as the curly braces nest so you do the stuff out to the matching brace at the end of the line. The curly braces serve to group the entire rest of the line as the required "do if true" part of the if statement. There is an optional "else, do if false" part but that isn't present here. A parenthetical note here, if you are using Programmer's Notepad you'll see that PN will show you the matching brace to one you select. This is really sweet and you need this, get it now.

The first expression in the "do if true" part is $ta = array_keys($_POST); $ta is a variable we pulled out of thin air. I call it 'ta' as a really short form of TemporaryArray. I don't call it TemporaryArray because I want the entire expression to fit on one line. array_keys($_POST); is what we are assigning to $ta. array_keys() is a built in PHP function that returns an array of keys from the key=>value pairs which comprise an array.

Arrays are a bit different in PHP; the index of the array is not constrained to be numeric, it can also be a string. This is very different from C and has profound and useful implications. $_POST is an array constructed from the HTML post data where the keys (indexes of the array) are the names of the inputs in the form being submitted and the values of the array are the values of those inputs. And yes, you can have arrays of arrays. PHP is nothing if not flexible.

So after the first expression is evaluated we have an array of keys in $ta. The second expression: for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";} is a for loop. This is a loop that iterates through a sequence of instructions a number of times and then quits. The basic logic goes: 1. set x to some number; 2. if x < some other number don't quit ; 3. do some thing; 4. increment x; 5. Go to 2 until quit. The actual formal expression is a bit more compact.

for($ti=0;$ti<count($ta);$ti++) is the control structure for the loop. The first expression inside the parenthesis assigns $ti (temporary index) the value 0. The second expression checks to see if $ti is less than count($ta). count is another built in PHP function that returns the number of keys in an array. If $ti is less than count($ta) then the statement(s) in the curly braces { } right after the closing parenthesis of the control structure are executed. After executing the "do_if_inbounds" statement, $ti is incremented.

The doing part looks like: {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";} echo emits a string of raw HTML to the page. What we are echoing is the concatenation of four strings. The concatenation operator is the period (.), really. The first string $ta[$ti] is fetched from the array of keys we put in $ta. The keys for the array $ta itself are numeric, as this is the default for the function array_keys. Other options are possible, we'll see those later.

As the loop increments the string in $ta[$ti] will be the name of each input in the previous form's post and that will be printed to the screen. The next string to be printed is an equals sign "=". Next is the string in the array $_POST[$ta[$ti]]. $_POST contains the key=>value pairs that are the previous form's inputs, $ta[$ti] contains the string that is the key for $_POST so that whole bit resolves to the value in $_POST pointed to by a particular named input. This cycles through all of the variables passed in the post. Hope that made sense.

The previous web page rewritten in PHP idiom looks like:

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' name='favorite_flavor' /> ";
	echo "<select onchange='updateMenu();' name='command'>";
		echo "<option value='Global Commands'>Global Commands</option>";
		echo "<option value='Add To List'>Add To List</option>";
		echo "<option value='Delete From List'>Delete From List</option>";
	echo "</select>";
	echo "<br />";
	echo "<input type='submit' name='submit' /> ";
?>
	</form>
  </body>
This is pretty boring, all we have done is put the PHP command echo in front of each line of HTML, quoted the HTML using double quotes, and replaced the double quotes " in the HTML with single quotes '. The last bit is important, HTML doesn't care about the difference between double and single quotes, PHP does. If you write all your HTML using single quotes you may then grab it right up and echo it without editing. Also, we added a semicolon ; to the end of each line of PHP, that's what indicates the end of the line.

One of the many things that PHP lets us do is sort of hide, or cram down information. The select in the previous example takes a lot of lines to make but is conceptually simple. Using PHP we can make the creation of that select appear as a single line by putting most of the work in another file. Copy the following text into a subdirectory you name "include", name the file "tutorial_functions.php".

<?php
/*		file: include/tutorial_functions.php
*		2012/02/13 - working initial cut
*		
*		Functions for tutorial
*/
function select_command($_POST, $base_name) {
	echo "<select onchange='updateMenu();' name='".$base_name."'>";	
	if ($base_name == 'command') {
		echo "<option value='Global Commands'>Global Commands</option>";
		echo "<option value='Add To List'>Add To List</option>";
		echo "<option value='Delete From List'>Delete From List</option>";
	} else {
		echo "<option value='Local Commands'>Local Commands</option>";
		echo "<option value='Chocolate'>Chocolate</option>";
		echo "<option value='Vanilla'>Vanilla</option>";
	}
	echo "</select><br />";
}
?>
to PHP
This is a function that makes a Select Object. A function is not an in-line replacement, rather it is a template for an instance of, in this case, a select object. The function's name is select_command. Information is passed into the function by the variables inside the parenthesis after the function name. All variables in PHP begin with $, that's how you know they are variables. Variables that are used by PHP and the System begin with $_, don't begin your variable names with underscore. In this case, we are passing in all of the inputs from the previous page in $_POST and a name for the particular select we are making when we call this function in $base_name.

The second line of the function begins with echo to emit raw HTML to make the select. The onchange='updateMenu();' bit is a directive to the select to call the script updateMenu(); when the value of the select changes. There is no script available to run, yet, so this is ignored. We'll be using this later. To understand the next new bit .$base_name. we'll need to talk a bit about strings.

Strings in PHP are collections of characters surrounded by double quotes. They can also be variables which have been assigned the value of strings, like $base_name in the example above. The PHP command echo expects one string as its argument. In the above example there are three distinct strings, two delimited by double quotes and the string contained in the value of $base_name. How we make these three strings one is by Concatenation of the strings using the . operator. Yes, the operator (symbol) for concatenation (mushing the strings together) is a period. Learn more about strings here.

So what we are doing with the second line is an echo of three strings mushed into one by the two periods surrounding .$base_name. followed by a ; (semicolon) to terminate the line.

The next line is an If Statement. The if statement is one method of directing program flow, or deciding things depending on how you think of this stuff. It has the form if(some_expression){do_if_true;}else{do_if_false;} The some_expression part has to evaluate to true or false. This is called a Boolean type. The semicolons after the do_if_true/false parts are required, the else do_if_false part is not required. The curley braces are used to group statements together and are optional if there is only one statement in each group.

The boolean expression in the example if($base_name == 'command') gets evaluated. If $base_name is equal to the string literal 'command' the expression evaluates to TRUE and the next statement is executed. The double equals == is the comparison operator for equals. A single equals = is an assignment operator which would assign the string 'command' to the variable $base_name, not what we want.

To recap, we have a function which when called creates an instance of a select which is named whatever name we passed in $base_name and depending on the value of that name makes one or the other type of select. After the select is constructed we echo a break to put whatever comes next on a new line.

Now we'll rework index.php, copy the following into the body part of the file.

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	include "include/tutorial_functions.php";  // a collection of functions for various stuff

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	select_command($_POST, $base_name="something_else"); // pick another command
	echo "<input type='submit' name='submit' /> ";
?>
	</form>
  </body>
What's changed here is the include directly after the debug line. This sticks the contents of the named file in-line in that spot. Since the file is a function it isn't executed (run) until it is called (invoked). We call that function twice with the lines that start select_command. If you save both files and mash Submit you should see something like:

The function we have constructed previously is pretty trivial and perhaps not very interesting but it does show how you can use a function as a template to create different instances of similar items.

What follows is a more amusing piece of code that actually does solve something. Specifying a quantity of stuff is a problem that comes up fairly often. Quantities have an amount and a unit, like 3 gallons or 5 feet. As a general rule you want to avoid allowing the user to type anything that will be used as an entry into a database, they will only break your heart (or tables). So selects are preferred to text inputs for pretty much everything. This generates a pair of selects named $prefix.'count' and $prefix.'units' right next to each other.

By this time when you see $ you should think variable. So you know that $prefix means some string that has been assigned to the variable $prefix. You should also think string literal when you see single quotes around some text, like 'count'. So when you see $prefix.'count' you are seeing the contents of the variable $prefix concatenated (.) with the string literal 'count' which results in one string.

Another thing you need to be aware of is that if something isn't a variable and it isn't quoted by either single or double quotes and it isn't an operator (<,>,=,+,-,...) and it looks like some_text($mumble_optional) then it is probably a function. Either one of yours or a PHP built in function. There is a nifty little search feature at the top of the the PHP documentation that defaults to searching the PHP function list. If you see something you don't understand that looks like a function(), go there for enlightenment grasshopper.

If you find yourself doing the same thing more that once you probably want to try to generalize it an make it into a function. Think of functions as tools that you are building. A few tools that do a a lot of things are better than a lot of tools that each do a few things. They are easier to find if they don't proliferate in an uncontrolled fashion.

A word about comments. PHP supports C style comments, which you don't see in the fragment below. I think comments are an unalloyed good, I just couldn't think of any to add to the code here that aren't blindingly obvious. Maybe I have been doing this too long. I do try to give variables and functions names that have readily apparent meaning.

Another thing I find useful is using text for option values in selects. If you don't specify a value an integer is assigned. Later when you evaluate the value you have an integer with no readily apparent meaning. In the past, integers were the preferred way of carrying value because memory was expensive and we tried to cram as much meaning into each bit as possible. Today memory is cheap, programmer's time is expensive. So any little thing we can do to make things blindingly obvious is a good thing.

Note that we are passing $Ingredient_Count and $Units into the function. This is because we can use the select as both a knob (to adjust things) and an indicator (to inform the user). Without special effort a select shows the first option on the list. We are passing the function the values that we want the select to stick at. If we don't provide values it will do the default behavior. In general we want to design objects that are as broadly useful as possible. This is why we didn't stick any labels on the selects in this function; any that we picked now would probably be wrong. We could pass one in, but it's a complication. Simple and general are what we strive for in functions.

function select_quantity($prefix, $Ingredient_Count, $Units)
{			
	echo "<select onchange='updateMenu();' name='".$prefix."count' >";
	for($i=0.5;$i<5;$i=$i+0.5) {
		if($i != $Ingredient_Count) echo "<option value='".$i."'>".$i."</option>";
		else echo "<option selected='selected' value='".$i."'>".$i."</option>";	
	}
	for($i=5;$i<33;$i++) { 
		if($i != $Ingredient_Count) echo "<option value='".$i."'>".$i."</option>";
		else echo "<option selected='selected' value='".$i."'>".$i."</option>";	
	}
	echo "</select>";
	echo "<select onchange='updateMenu();'  value='ea' name='".$prefix."units' >";
	if ('ea' != $Units) {echo "<option value='ea'>ea</option>";}
	else {echo "<option selected='selected' value='ea'>ea</option>";}
	if ('oz' != $Units) {echo "<option value='oz'>oz</option>";}
	else {echo "<option selected='selected' value='oz'>oz</option>";}
	if ('g' != $Units) {echo "<option value='g'>g</option>";}
	else {echo "<option selected='selected' value='g'>g</option>";}
	if ('lb' != $Units) {echo "<option value='lb'>lb</option>";}
	else {echo "<option selected='selected' value='lb'>lb</option>";}
	if ('tsp' != $Units) {echo "<option value='tsp'>tsp</option>";}
	else {echo "<option selected='selected' value='tsp'>tsp</option>";}
	if ('tbsp' != $Units) {echo "<option value='tbsp'>tbsp</option>";}
	else {echo "<option selected='selected' value='tbsp'>tbsp</option>";}
	echo "</select>";
}
The first line echos the opening tag of the select assigning the name of the select to be $prefix.'count' so we can identify this particular select. The next line is the beginning of a for loop which spans 4 lines. The control structure for the loop increments the temporary variable $i by 0.5 for each pass of the loop. We are doing this because we want the count part of this control to increment by half on the low end till the value 5 and then increment by 1 to 32 which is done in the second for loop. This gives us a finer control of the value on the low end where it is more important and the ability to choose the appropriate units give the user the ability to input any reasonable values for this application.

Thinking about reasonable values is part of what you want to do when you design a function. This particular application manages a household inventory. Initially I believed that most of what I was buying was groceries and this select design reflects that. The units are all weights and volumes which are useful in the kitchen and not lengths which are useful other places. After using the program for a bit I would add lengths to this control. I just haven't done it yet because I designed a general purpose work-around into the program that makes this flaw not painful enough to immediately address.

I'd also might add more numbers at the top incrementing by 5 from maybe 30 to 100. There is a limit to how many items you can usefully cram into a select though. One of the ways to manage that is to use a two stage select but that has some interesting complications we will get into later. Another useful variation would be to pass the function increment values and boundaries so that they wouldn't be fixed. That's probably useful enough to do RSN.

The third section of the function generates the units selector. In a select an option has two parts, a value and a label that appears to the user on the select itself. Explicitly calling out the value is not required, if it is absent an integer starting at 0 and incrementing for each additional option is provided. I like to use the same text for the value as the user sees; this way when I encounter the value in the program I know what it does, not just that it is '2'.

Now grab that code above and save it in ~www/tutorial/include/tutorial_functions.php just in front of the closing tag for the PHP at the end of the file. We'll be using this bit shortly. Now we want to rework ~www/tutorial/index.php so that the body looks like:

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	include "include/tutorial_functions.php";  // a collection of functions for various stuff

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	echo "<br />Food: ";
	select_quantity($prefix='food_'); // pick a quantity of food
	echo "<br />Drink: ";
	select_quantity($prefix='drink_'); // pick a quantity of drink
	echo "<input type='submit' name='submit' /> ";
?>
	</form>
  </body>

So save the files and hit Submit or Reload and pay attention. The first time you hit submit or reload the debug values aren't quite what you expect. Then you hit Submit again and they look OK. This is because the values in the debug area are the values that were on the previous screen. You need to keep that firmly in mind. These things become much more important later. You should now be seeing a screen that looks much like this:

So who ordered that break between Fave Flave: and Food:? Not what I had in mind. Poking about I notice that the select_command() function emits a <br /> at the end which is affecting our placement of related objects. Do not put positioning stuff in functions, it doesn't belong there. So fix select_command() in include/tutorial_functions.php so it doesn't emit that nasty break and save it away so it works properly. Good.

Another thing you might notice is that I entered 'chocolate => really' into the favorite_flavor text field. That => bit looks dangerously like an operator which ought to scare you. Remember, users can enter anything they can type into a text field and they are not usually looking to make life easy for you. They'll type the darnedest things... Don't give them the chance if you don't have to; if you do, pay attention, there are ways to mitigate the problem.

Another thing that is irritating about this program is that the controls and text inputs are not sticky. The data disappears when you Submit it. Usually that is what we want so that is the default behavior, but not always. Sometimes we want the data to stick. I want it to stick so that's what we'll do next.

So the current goal is to make the data stick from Submit to Submit. Copy the following code into the body of index.php.

  <body>
	<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	$FoodCount = $_POST["food_count"];  // Memory, Dr Memory 
	$FoodUnits = $_POST["food_units"];  
	$DrinkCount = $_POST["drink_count"]; 
	$DrinkUnits = $_POST["drink_units"];  
	$FavoriteFlavor = $_POST["favorite_flavor"]; 

	include "include/tutorial_functions.php";  // a collection of functions for various stuff

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' value='".$FavoriteFlavor."' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	echo "<br />Food: ";
	select_quantity($prefix='food_', $FoodCount, $FoodUnits); // pick a quantity of food
	echo "<br />Drink: ";
	select_quantity($prefix='drink_', $DrinkCount, $DrinkUnits); // pick a quantity of drink
	echo "<input type='submit' name='submit' /> ";
?>
	</form>
  </body>

The new parts are the block of assignments directly below our debugging statement and the use of those assigned values to inform the various elements of the form what their values should be. By now you recognize $_POST["food_count"] is an access to the array $_POST using the index "food_count" and assigning the value to $FoodCount.

Following the use of $FoodCount down to the function select_quantity() we see that $FoodCount is being fed to what we labeled $Ingredient_Count in the function. It might be occurring to us now that maybe $Ingredient_Count isn't the best sort of function name, it's too specific. Just $Count might be a more appropriate name, maybe $Amount, mumble.

You might also notice that the names don't match between the function call in index.php and the function template in tutorial_functions.php. This is a very good thing. This lets us change the poor names in our function template to good ones without having to find everywhere they were used and change those too. What does have to match is the order of the variables in function call and the function itself. It is best to put the required variables first in the function and the optional variables last.

But the really clever bits of this have probably passed unnoticed. If you look at the code above it makes sense. Once you understand the general syntax of C and a few operators the biggest help or hindrance to producing readable code is reasonable names. Reasonable descriptive names for variables and functions will make your life a lot easier. If you doubt the wisdom of this take a close look at the debug line again.

I know you have already mashed submit, I hope you saw something like:

But there is still something bothersome about the form. That Submit button looks like a pretty much otherwise useless piece of digital flotsam; let's get rid of it. What we would really like is for the form to be submitted when the command select is changed. This is going to need for us to do a bit of translation in the web browser. A change in the value of command needs to be transmogrified into the push of the vanished Submit button. We can't do this with PHP; it runs on the server, so it's

JavaScript to the rescue!

JavaScript for tutorial:

JavaScript runs on the client-side as opposed to the server-side where PHP runs. This makes it beautifully complementary to PHP. In another complementary fashion we are going to be editing the head of index.php not the body for this piece. Scripts may appear in-line, but I like to segregate them into their own little ghetto in the head. Replace all of the script element in the head with the following:

    <script type="text/javascript">
		/*	These scripts are available globally to all the included files.  The scripts
		*	are executed by the client machine in response to inputs by the user, typing
		*	input and selecting menus and such.  
		*
		*	Unlike the php source, these scripts are visible to the client when view source
		*	is used. The scrip functions are generally called by form elements when they
		*	are manipulated by the user, and cause things to happen on the client page.
		*
		*	It is very important in general to test all objects for non-null values before
		*	attempting to write to them as writing to a null object will hang the script.
		*	You can tell this is happening when you see that the form doesn't update when
		*	the values of the <selects> are changed.
		*/
		function formSubmit() 
		{	// reload frm1 (everything is frm1) with the current input values
			document.getElementById('frm1').submit();
		}
		function updateMenu() // runs every time any menu <select> is updated
		{	// 			
			formSubmit();
		}
    </script>
Now let's chat. In the opening tag we declare the script type to be text/javascript. We don't have to do this, it's the default. It's nice to make explicit the default though so that everybody is clear on the concept. Inside JavaScript C style comments work. Outside, HTML style comments are necessary. All of the comments above are true and useful.

Those comments are pretty typical of what I write for comments. I'm lazy, to do this tutorial I swiped all this stuff from a program I already had written and working and deleted the stuff that isn't relevant. I don't like to write about what the code is doing; if I have named things properly I can read that. I comment about why the code is doing what it is doing. That I can't read in the code and I am unlikely to remember from one day to the next.

Our selects pretty much all have onchange='updateMenu();' in the opening tag. The attribute onchange is what we call an event. An event is something that happens to an element like changing value (onchange) or having the mouse move over the element (onmouseover). Events are things which happen to elements; think of them as verbs for elements. Mash here for a more complete treatment of events.

The event onchange causes a call to the function updateMenu() which calls formSubmit() which actually does the heavy lifting. The reason we didn't call formSubmit() directly is that we might want to do other things when a select changes that we don't want to do when some other element wants to submit the form. The actual submitting gets done by the document.getElementById('frm1').submit(); statement. To explain that statement we have to get into something known as the Document Object Model.

I don't want to talk in detail about DOM right now so just take a gander at that little bit of magic that simulates pushing the submit button and then look carefully in the opening tag of the form in the modified body that follows:

  <body>
	<form id="frm1" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	$FoodCount = $_POST["food_count"];  // Memory, Dr Memory 
	$FoodUnits = $_POST["food_units"];  
	$DrinkCount = $_POST["drink_count"]; 
	$DrinkUnits = $_POST["drink_units"];  
	$FavoriteFlavor = $_POST["favorite_flavor"]; 

	include "include/tutorial_functions.php";  // a collection of functions for various stuff

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' value='".$FavoriteFlavor."' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	echo "<br />Food: ";
	select_quantity($prefix='food_', $FoodCount, $FoodUnits); // pick a quantity of food
	echo "<br />Drink: ";
	select_quantity($prefix='drink_', $DrinkCount, $DrinkUnits); // pick a quantity of drink
	//echo "<input type='submit' name='submit' /> ";
?>
	</form>
  </body>
What's different about the opening tag of the form is id="frm1". You can find all of the standard attributes here, and id is one. The short story is that it is a unique identifier for our form. The entire string document.getElementById('frm1').submit(); is DOMinese for "submit 'frm1' in this document".

One more thing to notice is that the line that echoed out the raw HTML for our former Submit button has been commented out. If you don't do this the button and the DOM fight and things don't work. You want things to work. Don't have two objects try to do the same thing, it's bad and wasteful (also bad).

You'll find that if you copy the script and the body into index.php, save and refresh, that the Submit button disappears and that the form is now submitted every time the value of a select changes. Give it a whirl.

To recap, we learned about events, which are like verbs for elements. We learned that we can use JavaScript to link events to the actions of elements on the browser's page through the Document Object Model. And that the DOM itself is a big black box at the moment. That will change.

DOM:

Document Object Model: Or how I learned to love OOP...

Object Oriented Programming is the latest fad in code-smithing, all the cool kids have been doing it for 20+ years. The previous model was procedural, you called procedures with a pointer to data and the procedure munged the data and returned a value indicating success or failure or something... Procedures, algorithms, were separate from data and you called one to operate on the other.

The Object Model rolls procedures and data into a single fur-ball called an object. Procedures get renamed methods (I guess so you know it's an object) and the data, which gets renamed properties is inside the object and is usually divided into public and private parts (methods too). The public parts are the bits you can see and use.

Looking at the money bit from the last section document.getElementById('frm1').submit(); In this fragment, document is an object. getElementById('frm1') is a method of the object document which resolves to an object which is an element of type form with the id 'frm1'. This object has a method submit() which involks the Submit Input on the element object. Clear?

DOM can be viewed as an inverted tree with the document at the top. All of the elements of the document (page of HTML) are accessible if you give them a unique id="mumble". getElementById() is the best method of referring to elements in JavaScript. There is a method getElementsByTagName() which gets you a NodeList of all the elements with name="mumble" but it's easier just to use id="mumble" and ensure that id is unique.

You can look at the methods for the element object here. The most useful is setAttribute() which can be used to force inputs to desired values and states. But if you look to the left on the screen you will see a list of HTML DOM Objects. This is where the gold lies if you want to twiddle elements from JavaScript.

The take away here is that those elements on your page that you want to manipulate with JavaScript need to have a unique id="mumble". You may then refer to that element as document.getElementById('mumble').method();. The methods that are available to the object (element) depend on the object. In the tutorial example the object was a form and one of the methods of a form is submit();.

One of the hazards of JavaScript is that it fails silently. This is probably a good idea in a client side scripting language, if a particular thing is unavailable at the moment you don't want error messages spewed all over the user's screen. But it does make it annoying to debug. One of the things that will definitely cause JavaScript to fail is any attempt to write to a NULL object. Any object that doesn't appear on the current page is NULL. This is not as nonsensical as it seems. Your program may have the notion of an object that you just aren't rendering at the moment because the time is not right. If your script tries to write to that object when it has not been instantiated the script stops silently.

DOM is just another way to look at the document. We have been thinking of the document as a collection of HTML that gets spewed by the server to the client for rendering but it really is more complicated than that, and the DOM gives us a way to talk about it.

Editorial Rant: I've heard a lot of whining from old farts about how OOP doesn't make sense, or that it's too hard. Get over it. It turns out to be a fairly useful way of thinking about things and frankly, who cares if the actual bits don't work that way. In the early '90's I wrote a Java application (not script, running on the iron) of >100K lines in less than a year which maintained a schedule in an arbitrary database, built a website to sell time in that schedule, routinely displayed images and video and even answered and took reservations over the phone. It was, of course, wildly networked. We managed to sell about a thousand systems and never had a user report a bug. It is my understanding that most of them are in use to this day. End of rant.

MySQL:


xkcd: exploits of a mom. For more, click pic.

The first step in using a database is to create one. The easy way to do this is directly using phpMyAdmin. Type localhost/phpmyadmin/ into your browser's address bar and hit CR. Select the Databases tab and type 'tutorial_db' into the textbox under Create New Database. Select 'ascii_bin' under Collate (you are selecting a character set for the db here). Bug (select, hit-it) Create. You should get feedback that "Database tutorial_db has been created" and you should see it appear in your list of databases.

Later we will discuss creating the db programmatically using PHP.

Copy the following code into a file named ~www/tutorial/include/connect.php

<?php
$db = "tutorial_db";
$link = mysql_connect('localhost', 'admin', 'password');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
echo 'Connected successfully<br />';
mysql_select_db($db) or die(mysql_error());
?>
This fragment is not a function but an in-line bit of code that appears wherever we type include 'include/connect.php'; It just drops right in, like text from the gods. What it does is connects us to our database, using the name and password provided earlier, and informs us that we have successfully connected. The "or die" construct is interesting. If we fail to successfully connect the PHP script quits, Dead Right There. There is a very helpful error log though, you should find it soon. Part of the beauty of PHP is that this fragment (with our login name and password) never appears in the raw HTML emitted by the server. We then select, as opposed to connect to our database to proceed further. Copy the following code into the body of ~www/tutorial/index.php to make sure we are all on the same page.
  <body>
	<form id="frm1" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	$FoodCount = $_POST["food_count"];  // Memory, Dr Memory 
	$FoodUnits = $_POST["food_units"];  
	$DrinkCount = $_POST["drink_count"]; 
	$DrinkUnits = $_POST["drink_units"];  
	$FavoriteFlavor = $_POST["favorite_flavor"]; 

	include "include/tutorial_functions.php";  // a collection of functions for various stuff

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' value='".$FavoriteFlavor."' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	echo "<br />Food: ";
	select_quantity($prefix='food_', $FoodCount, $FoodUnits); // pick a quantity of food
	echo "<br />Drink: ";
	select_quantity($prefix='drink_', $DrinkCount, $DrinkUnits); // pick a quantity of drink

	echo "<br />";
	include 'include/connect.php'; // connects us to tutorial_db
?>
	</form>
  </body>
The new thing here is the include/connect.php at the bottom. If you do the usual save/submit cycle you should see "Connected successfully" from the include file telling you all is good. We will soon eliminate the line generating that happy feedback as it will be in our way, but for now it lets us know everything is working as it should.

Now we need to add a Table. In this case, a table is not furniture but a template for a collection of data. The data we are collecting for this little program is about stuff we buy at the store. The first table we need is one that represents items. I've copied below the existing table I am using.

	 1	name			varchar(64)	latin1_swedish_ci
	 2	upc			bigint(16)		No	None	
	 3	menus			varchar(64)	latin1_swedish_ci
	 4	price			varchar(16)	latin1_swedish_ci
	 5	amount			varchar(32)	latin1_swedish_ci
	 6	calories_unit		varchar(32)	latin1_swedish_ci
	 7	suppliers		varchar(64)	latin1_swedish_ci
	 8	handling		int(11)		No	None
	 9	url			varchar(64)	latin1_swedish_ci
	 10	level			double		No	None
	 11	reorder			float		No	None

  • name
  • - Is pretty much what appears on the label that enables our buyers to recognize what we wanted. We have a choice here in how big we want to make the name. At the time, 64 characters seemed to be plenty. In retrospect, after a bit of use, I'd make that 256. Memory and disk are cheap, aggravation is not.
  • upc
  • - We need a unique identifier and the name just won't cut it. One good reason to use UPC is that everybody else uses it and if you ever want to hook this program up to an outside source of data, well, you'll be talking about the same stuff. This is typed as a bigint which is easy to search. We'll be using this as a primary key meaning we will mostly be using this as an index into the db so we care. UPC's are 12 digit number (mostly) with a checksum digit as the least significant.
  • menus
  • - I was a bit conflicted by this. Items need to be assigned to individual menus like 'dairy' and 'freezer' or else they become unwieldy with the mass of items. I initially thought that these menus might need to be individualized by user by experience has shown that they really need to be keyed to the store where the items are mainly purchased. Anyway, this is a bit misguided and I'll talk more about it later.
  • price
  • - Pretty obvious, what did we last pay?
  • amount
  • - How much stuff is in the box?
  • calories_unit
  • - Used for a daily calorie accumulator/meal deal.
  • suppliers
  • - This is text, but also an index to a supplier table. More Later.
  • handling
  • - The thinking here was that some items require special handling, freezer, refrigerator, no-flame... Hasn't been useful so far.
  • url
  • - This was included as possibly a pointer to an image of the product. It needs to be a lot longer.
  • level
  • - How much stuff do we have in inventory?
  • reorder
  • - And when should we get more.

Tables are where data is stored in a database. It's convenient to think of tables as rows of individual items and columns of data fields. One of the columns is designated the primary key and the values in that column must be unique, each row's value must be different. Think of the primary key as the one true name of the record or individual entry (row) in the table.

The list above comprise the columns of the table. In general it is better to overdo than to fall short on field sizes. Don't be ridiculous, we don't need 4096K to store a product name, but it is easy to make fields go away or be smaller. Before you have accumulated significant data it is easy to adjust fields in general. Going big and cutting back when you have some experience seems to be a path that has worked for me.

Another database trick you want to be very aware of: If you are storing the same data in two different places you are doing it wrong. Consider the table above, there is a field named 'suppliers' and its a varchar(64). You might naively think we are going to put the supplier's name and address in that field, but that would be wrong. Many (most, really) of the items come from the same supplier. Imagine row after row containing the data 'Wallmart in Milton, FL 32570' over and over again, row after row. Pretty dreary all this duplication of text.

So what we do is create another table called 'suppliers' with a numeric primary key and a bunch of fields that have the supplier name, address, phone, contact, url, last conversation and anything else we can think of because we are only going to store this bit once and use that primary key in the suppliers field of the item table data.

So why is suppliers a text field? Because we may have multiple suppliers for the same item. We can store them by saving their primary keys as Comma Separated Values (CSV) in the suppliers field. There are downsides to this we will discuss later.

The next thing to do is write some code that will check to see if the tables we are interested in are present, and if not, to create them. Being lazy, for this application I just used phpMyAdmin to define the tables, but if you want to deploy an application to some folks and have them collect their own data you might want your program to set up the tables. So, I'll go away now and work that out and be back with some code that creates tables.

I hope some of you are being entertained. I know I am...

When we last left off I had erroneously stated that you can't create a db from PHP. More accurately, I had tried for a little bit and given up and just whacked it off with phpMyAdmin, tables too. So here is the promised code to create a db and tables from PHP. First, to make sure we are all on the same page, here are the three files we will be playing with in their entirety.

~www/tutorial/index.php

<html>
  <head>
    <title>
	Page title goes here...
    </title>
    <style>
	CSS Style, if you've got it...
    </style>
    <script type="text/javascript">
		/*	These scripts are available globally to all the included files.  The scripts
		*	are executed by the client machine in response to inputs by the user, typing
		*	input and selecting menus and such.  
		*
		*	Unlike the php source, these scripts are visible to the client when view source
		*	is used. The scrip functions are generally called by form elements when they
		*	are manipulated by the user, and cause things to happen on the client page.
		*
		*	It is very important in general to test all objects for non-null values before
		*	attempting to write to them as writing to a null object will hang the script.
		*	You can tell this is happening when you see that the form doesn't update when
		*	the values of the <selects> are changed.
		*/
		function formSubmit() 
		{	// reload frm1 (everything is frm1) with the current input values
			document.getElementById('frm1').submit();
		}
		function updateMenu() // runs every time any menu <select> is updated
		{	// 			
			formSubmit();
		}
    </script>
  </head>
  <body>
	<form id="frm1" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {echo "In index.php<br />";$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	$FoodCount = $_POST["food_count"];  // Memory, Dr Memory 
	$FoodUnits = $_POST["food_units"];  
	$DrinkCount = $_POST["drink_count"]; 
	$DrinkUnits = $_POST["drink_units"];  
	$FavoriteFlavor = $_POST["favorite_flavor"]; 

	include "include/tutorial_functions.php";  // a collection of functions for tutorial
	include "include/connect.php";  // keys for db login
	include "include/check_tables.php";  // see that db tables are present, create if not

	echo "Hello World...<br />";
	echo "Fave Flav:<input type='text' value='".$FavoriteFlavor."' name='favorite_flavor' /> ";
	select_command($_POST, $base_name="command"); // pick a command
	echo "<br />Food: ";
	select_quantity($prefix='food_', $FoodCount, $FoodUnits); // pick a quantity of food
	echo "<br />Drink: ";
	select_quantity($prefix='drink_', $DrinkCount, $DrinkUnits); // pick a quantity of drink
	echo "<br />";
	echo "Hi there<br />";

	check_tables(); // check to see that tables present
	echo "<br />Hi Again<br />";

?>
	</form>
  </body>
</html>

~www/tutorial/include/connect.php
<?php
// this is an in-line and the only place where the db username
// and password should appear.
$debug = true;
$db = "tutorial_db";
$link = mysql_connect('localhost', 'admin', 'password');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
if($debug == true) {echo 'Connected to MySQL successfully<br>';}
?>
~www/tutorial/include/check_tables.php
<?php
/*		file: include/check_tables.php
*		2012/02/17 - working initial cut
*		
*		Check for existance of tables and create any
*		missing ones.
*/
function check_tables() {
// Usage without mysql_list_dbs() deprecated
	$debug = true;
	include 'include/connect.php'; // connects us to db
	if($debug == true) {echo 'Connected SQL link='.$link.'<br />';}
	$res = mysql_query("SHOW DATABASES");
	if($debug == true) {echo "checking database...<br />";}
	while ($row = mysql_fetch_assoc($res)) {
		echo $row['Database'] . "\n";
	}
}
	// Create items table
function create_items_table() {
	include 'include/connect.php'; // connects us to tutorial_db
	echo "Creating Table items.<br />";
	$sql = "CREATE TABLE items
	(
	name varchar(256),
	upc bigint(16) NOT NULL,
	menus varchar(64),
	price varchar(32),
	amount varchar(32),
	calories_unit varchar(32),
	suppliers varchar(32),
	handling int(11),
	url varchar(512),
	level double,
	reorder float,
	CONSTRAINT item_pk	// primary key
		PRIMARY KEY (upc),
	CONSTRAINT item_uq	// unique fields
		UNIQUE (upc)
	)";		
	// Execute query
	mysql_query($sql,$link);
	mysql_close($link);	
}
?>

These have been edited a bit to suit my nefarious purposes so please do cut and paste. The main differences here are that we are making a connection to the db and getting a list of the databases present. We can then check to see if our db is among them. If so, we'll check the tables and if they are not present we will create them. We won't ask permission because without tables the rest of the tutorial is pretty useless, but in a real application it is usually wise to ask before doing anything rash.

After you have saved the files away and diddled one of the selects to get a refresh, you should see something like:

Whoops! See below:

drink_units=oz
Connected to MySQL successfully
Hello World...
Who ordered that? Looks like we have treated an inline, connect.php, like a collection of functions and it hurt us. So remove the include to prevent unnecessary connects. Fix this to be sure you understand.

The other thing that is going on here, the thing that we planned, is that we are connecting to the db successfully with a particular Resource id and we got a list of databases. Ours, "tutorial_db" is among them because we created it earlier using phpMyAdmin. Using that same tool, let's blow it away so we can recreate it auto-magically.

A quick word about debugging here. I use echo extensively for debugging (and the error logs). Sometimes it is temporary, like "Hi there". These statements get blown away forever when they have served their purpose. There are others though, that I think may just get used again, and they get hidden by if($debug==true){spray_information_to_page;} in the normal course of things. As the number of files grow, I like to identify what file or function the debugging information came from so I can turn it off. This is why "In index.php" now appears at the top of the output.

So let's add a little bit to our check_tables() function to create the necessary db and tables.

function check_tables() {
// Usage without mysql_list_dbs() deprecated
	include 'include/connect.php'; // connects us to db
	$debug = true;
	if($debug == true){echo 'Connected SQL link='.$link.'<br />';}
	$res = mysql_query("SHOW DATABASES");
	if($debug == true){echo "checking database...<br />";}
	$present = false;
	while ($row = mysql_fetch_assoc($res)) {
		if($debug == true){echo $row['Database']." ";}
		if($row['Database'] == $db){$present = true;}
	}
	if($debug == true){echo "<br />";}
	if($present == false) { // Create db
		echo "Database ".$db." not present. Creating...<br />";
		$sql = 'CREATE DATABASE '.$db;
		if (mysql_query($sql, $link)) {
			echo "Database ".$db." created successfully<br />";
		} else {
			echo 'Error creating '.$db.': ' . mysql_error() . "<br />";
			die(mysql_error());
		}
	}
	mysql_select_db($db);
	$sql = "SHOW TABLES FROM ".$db;
	$result = mysql_query($sql);
	if (!$result) {
		echo "DB Error, could not list tables\n";
		echo 'MySQL Error: ' . mysql_error();
		exit;
	}
	$items_present = false;
	while ($row = mysql_fetch_row($result)) {
		if($debug == true){echo "Table: {$row[0]} <br />";}
		//echo "Table: ."$row[0]." ";
		if($row[0] == 'items') {$items_present = true;}
	}
	if($items_present == false) { //make items table
		create_items_table();
	}
	mysql_free_result($result);
}

Copy, save, submit and you should see something like:

Which shows a database named 'tutorial_db' and table called 'items' created. Yea! Next we'll talk more about SQL in general.

We are using a version of SQL called MySQL. There are about 5 major flavors of SQL, all pretty much mutually incompatible at the level of fine detail. At the same time, they all work substantially alike. Understanding one version gets you 97% of the way to understanding any other. SQL was developed originally by IBM in the early 1970's and called SEQUEL. It was renamed due to a trademark dispute.

A pretty good tutorial on SQL in general can be found here. SQL is an acronym for Structured Query Language. Some formulations replace Structured with something less complementary. It became an ANSI standard in 1987 (the reason there are only five versions) which has been enhanced by vendors several times since then in the interest of keeping their customers locked to their particular product.

It's a language like any other. There are control structures (CASE statements) and a blizzard of data types, different for each version, of course. The whole business is optimized to work on data structured as tables. Think rows of individual entries with columns of fields of different data types. SQL is used to sort through a collection of such data looking for rows which meet the specification of the moment and returning those rows to the user for further processing.

Most of the actual mechanics of what we will be doing is putting together a string in the variable $sql (called a query in SQL-speak) and stuffing it into the function

  $res = mysql_query($sql);
with the results ending up in the array $res. It's the query string itself that does most of the work communicating with the db. The formulation
  while ($row = mysql_fetch_row($result)) {paw_through_the_rows;}
lets you step through the rows of results looking for what you want. Ninety five percent of what we do is simple variations on this theme.

Most of the art of SQL lies in designing the tables. There are definitely right and wrong ways to go about it. You can even make the wrong way work, for a while. I'm not a database guy and I do have a penchant for learning things the hard way. I've been trying to formulate general rules for db design but have only come up with one so far. If you find yourself storing the same information in two different places, you are doing it wrong.

We have already designed one table. We slipped that in with the function create_items_table() in ~www/tutorial/check_tables.php. This is a table of items one might buy at the store. We enumerated the list of fields earlier and that list is present in the function above. One of those fields is called menu and it tells us which menu (a grouping) that item is to be found on. We need to somehow group items so as to keep the selects for the items from becoming unwieldy.

The initial thought was to group like items with like. Drinks with drinks and dairy with dairy and such. This turns out to be not such a bad idea and almost correct. The people doing the actual buying wanted a list organized by where the items physically were in the store. This meant that some items that were say fresh orange juice were not stored with the other drinks but instead are with the dairy items. Some flexibility in the menus is obviously required.

So we need a table for the item menus. Let's call it item_menus. It needs two fields, index0 type int(11) and name type varchar(64). We are using index0 instead of index for a name because the name index is special to SQL, name does not appear to be special. This is the table's primary key and it is also used to order the menu. The name part of the table is the text that actually appears in the menu used to organize the items.

I've reworked this file a bit so stuff this whole mess into ~www/tutorial/include/check_tables.php

<?php
/*		file: include/check_tables.php
*		2012/02/17 - working initial cut
*		2012/02/20 - added creating db, items
*		2012/02/20 - added creating item_menus
*		
*		Check for existance of tables and create any
*		missing ones.
*/
function check_tables() {
// Usage without mysql_list_dbs() deprecated
	include 'include/connect.php'; // connects us to db
	$debug = true;
	if($debug == true){echo 'In check_tables() Connected SQL link='.$link.'<br />';}
	$res = mysql_query("SHOW DATABASES");
	if($debug == true){echo "checking database...<br />";}
	$present = false;
	while ($row = mysql_fetch_assoc($res)) {
		if($debug == true){echo $row['Database']." ";}
		if($row['Database'] == $db){$present = true;}
	}
	if($debug == true){echo "<br />";}
	if($present == false) { // db not present, creat it.
		echo "Database ".$db." not present. Creating...<br />";
		$sql = 'CREATE DATABASE '.$db;
		if (mysql_query($sql, $link)) {
			echo "Database ".$db." created successfully<br />";
		} else {
			echo 'Error creating '.$db.': ' . mysql_error() . "<br />";
			die(mysql_error()); // die a horrible death, can't go on...
		}
	}
	mysql_select_db($db);
	$sql = "SHOW TABLES FROM ".$db;
	$result = mysql_query($sql);
	if (!$result) {
		echo "DB Error, could not list tables\n";
		echo 'MySQL Error: ' . mysql_error();
		exit; // die a horrible death, can't go on...
	}
	$items_present = false; // flags for table creation
	$item_menus_present = false;
	while ($row = mysql_fetch_row($result)) { // paw through the results
		if($debug == true){echo "Table: {$row[0]} <br />";}
		//echo "Table: ."$row[0]." ";
		if($row[0] == 'items') {$items_present = true;}
		if($row[0] == 'item_menus') {$item_menus_present = true;}
	}
	mysql_free_result($result); //return some memory
	if($items_present == false) { //make items table
		create_items_table();
	}
	if($item_menus_present == false) { //make item_menus table
		create_item_menus_table();
	}
}
	// Create items table
function create_items_table() {
	include 'include/connect.php'; // connects us to tutorial_db
	echo "Creating Table items. <br />";
	// do NOT put any comments in the string below
	$sql = "CREATE TABLE items (
	name varchar(256),
	upc bigint(16) NOT NULL,
	menus varchar(64),
	price varchar(32),
	amount varchar(32),
	calories_unit varchar(32),
	suppliers varchar(32),
	handling int(11),
	url varchar(512),
	level double,
	reorder float,
	CONSTRAINT item_pk	
		PRIMARY KEY (upc),
	CONSTRAINT item_uq	
		UNIQUE (upc)
	)";		
	// Execute query
	$res = mysql_query($sql);
	if($debug == true){echo "Result = ".$res;}
	mysql_close($link);	// we're done, clean up.
}
	// Create item menus table
function create_item_menus_table() {
	include 'include/connect.php'; // connects us to tutorial_db
	echo "Creating Table item_menus. <br />";
	// do NOT put any comments in the string below
	$sql = "CREATE TABLE item_menus (
	index0 int(11) NOT NULL,
	name varchar(64) NOT NULL,
	CONSTRAINT item_menus_pk	
		PRIMARY KEY (index0),
	CONSTRAINT item_menus_uq	
		UNIQUE (name)
	)";		
	// Execute query
	$res = mysql_query($sql);
	if($debug == true){echo "Result = ".$res;}
	mysql_close($link);	// we're done, clean up.
}
?>
The rework is in the table creation logic and in closing the links after individual table creation. This is probably a good idea to let the system reclaim memory in an orderly fashion. The system will also probably reclaim the memory when a new $link is opened, at least it should. Better to be explicit and safe than rely on how things should be and sorry. A few comments have been added for clarity. Hey, I tried.

Another thing to be aware of is that this whole check_tables() business runs every time the page is refreshed. You might not want to do that, it consumes resources (CPU) that you might want for something else, like running the program with > 10K users. It would be wise to only run this function when there are new tables to be made. On the other paw, it isn't very computationally expensive. For the moment we will leave things as they are. We'll be slipping new tables in pretty regularly for a while.

So, to recap; we know how to check to see if a db is present and create it if not. We can check for the presence of individual tables and create them if they are not in the db. In the future, for additional tables I will provide the function for table creation and you will graft it into check_tables() so that it all works. You should be able to do this now. If not, I need to know because I may not be communicating clearly.

Writing the Program:

Server New Connect Edit Menu Select Generic Edit Items:

So now we have all of the pieces in place to begin writing our program and our understanding of all of the various bits is sufficient to proceed. There is a new factor I would like to introduce here, the notion of a hidden variable. This is an input in a form that doesn't appear on the rendered page. It's very useful in passing state information from page view to page view; it's really all the same page.

A hidden variable looks like this <input id='edit_menu_exists_id' type='hidden' value='exists' name='edit_menu_exists'> The simple existence of the variable can contain the information or you can attach a value to it. This variable is going to be used to indicate how we are editing items in the database. There are three types of edit we can do, add, edit and delete. We can also note that a page (or display interface) exists. We use simple obvious strings to convey those values to make the program more readable.

In the code below there is a hidden variable in the function edit_menu() that only shows up in $_POST when an instance of function edit_menu() exists. We assign the value of that variable to $EM_exists and it serves as a flag to let us know if we are editing menus or not.

We can light up an instance of edit_menu() by selecting 'Edit Menus' at the bottom of the global command select created by select_command($_POST); We removed the silly switch and base_name business, that was just for the tutorial. If we do select 'Edit Menus' the form is submitted with the value of the input 'command' as 'Edit Menus' which will appear in the array $_POST["command"] and gets stuffed into $Command.

When we come to the if statement $Command == 'Edit Menus' is satisfied and none of the other variables exist so they are not a factor. edit_menu($_POST); gets invoked (called, executed) and an instance of edit_menu() is created with all of its various objects. We'll see those later.

The newly created instance creates it's hidden variable which eventually lands in $EM_exists which lets us "latch" the instance of edit_menu() until the 'Exit Edit Menus' condition in the if statement is satisfied.

Replace the entire body of ~www/tutorial/index.php with the following:

 
  <body>
	<form id="frm1" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php 
$debug = true;
if($debug) {echo "In index.php<br />";$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br />";}}

	$Command = $_POST["command"];  // Memory, Dr Memory; global command select value
	$EM_command = $_POST["edit_menu_command"];  // edit_menu command select value
	$EM_exists = $_POST["edit_menu_exists"];  // edit_menu exists
	$New_menu = htmlspecialchars_decode($_POST["new_menu"]);  // used in edit_menus as a source (is a textfield)
	$Current_menu = $_POST["menu_current"];
	$Feedback = ''; // Global string, produced by everybody, consumed by index.php and printed at the bottom of the page.

	include "include/tutorial_functions.php";  // a collection of functions for tutorial
	include "include/check_tables.php";  // see that db tables are present, create if not
	include "include/edit_menu.php";  // edit the menu catagories.
	include "include/select_generic.php";  // a generic select into the db

	select_command($_POST); // pick a command
	echo "<br />";
	check_tables(); // check to see that tables present
	
	if  (($Command == 'Edit Menus'  || $EM_exists == 'exists') && $EM_command != 'Exit Edit Menus')  {  
		edit_menu($_POST);  
	} 
	echo "<p class='fb'>".$Feedback."</p>"; // output at bottom of page
	echo "<p class='err'>".$Error."</p>"; // using the css defined at the beginning of the page
?>
	</form>
  </body>

We include two new .php files which we'll be using later. When they are missing things should fail silently but an error message is recorded in the error log. You have found the error log, yes?

The first file, edit_menu.php, we discussed above, it lets you create and edit menus (categories) for items you purchase. The second file, select_generic.php is used by edit_menu() and a whole lot more. With select_generic() we can begin to see the possibilities of maybe making all of this not so dreary and confusing. We'll get to that too.

Near the bottom is code that prints the contents of a couple of variables that are used to report errors and feedback. There is a new construct <p class='fb'>".$Feedback."</p>. This is the first sighting of the actual use of CSS. What we have done is assigned this entire paragraph to the class 'fb' (feedback). Later we will color it blue but that's a distraction for now.

Another thing to notice as we move forward is that the pages now start to seem to have two parts. There is a noun part that makes objects that show up on the page and there is a verb part that controls the action. I like to group the action at the end of the file. This seems to make sense, first you make things and then you act on them. When we Submit the page all of the values of the inputs with the names of their instances (most of the objects we are creating) are posted back to the server.

Back at the Server: program

Whoops! Un-comment $Feedback = ""; in index.php, the example above. Sorry, slip of the mind. That statement zeros out that variable before it gets processed by the grammar of the includes. That is where it sees most of its use.

Back at the server, the very first thing we do in the form (modulo debug) is unwrap all of those inputs in the $_POST and stuff them into variables so that they can be evaluated by the verb part of the include files that follow the assignment. The include files to this point have been mostly functions. Functions don't actually exist until they are called. The verb parts, the included grammar (I did make that one up), do exist and the logic of it is executed as the files are included (processed by PHP) while it reads and evaluates the file. In order for the variables to be usable by the included grammar the variable assignment must precede the included files. You see this in index.php which is currently the only file with includes. This will also change.

We have redone the function select_command() so that it only need be passed the variable $_POST. By unwrapping $_POST we can get to all of the current state. We use a bit of that state, $EI_exists, to modify the creation of this select. We will be seeing this work shortly. We also added a new function, edit_menu_command() which creates a command select for the function edit_menu().

Replace the function select_command() in ~www/tutorial/include/tutorial_function.php with the following:

function select_command($_POST) {
	$EI_exists = $_POST["edit_item_exists"];
	$Command = $_POST["command"];

	echo "<select onchange='updateMenu();' name='command'>";	
	echo "<optgroup label=\"List Operations\">";
	echo "<option value='Global Commands'>Global Commands</option>";
	echo "<option value='Add To List'>Add To List</option>";
	echo "<option value='Delete From List'>Delete From List</option>";
	echo "</optgroup>";
	echo "<optgroup label=\"DB Operations\">"; // are we permitted to save item?
	if(($Command != 'Save Item to DB' && $Command != 'Continue Unchanged') && ($EI_exists == 'add' || $EI_exists == 'edit' || $EI_exists == 'delete'
		|| $Command == 'Add Item to DB' || $Command == 'Edit Item in DB' || $Command == 'Delete Item in DB')) { // add the ask $Command == 
			echo "<option value='Save Item to DB'>Save Item to DB</option>";
			echo "<option value='Continue Unchanged'>Continue Unchanged</option>";
	} else {
		echo "<option value='Add Item to DB'>Add Item to DB</option>";
		echo "<option value='Edit Item in DB'>Edit Item in DB</option>";
		echo "<option value='Delete Item in DB'>Delete Item in DB</option>";
	}
	echo "</optgroup>";
	echo "</optgroup>";
	echo "<optgroup label=\"List Operations\">";
	echo "<option value='Edit Menus'>Edit Menus</option>";
	echo "</optgroup>";
	echo "</select>";
}

function edit_menu_command() {
	echo "<select onchange='updateMenu();' name='edit_menu_command'>";	
	echo "<optgroup label='Menu Editing'>";
	echo "<option value='Menu Edit Commands'>Menu Edit Commands</option>";
	echo "<option value='Add Menu'>Add Menu</option>";
	echo "<option value='Rename Menu'>Rename Menu</option>";
	echo "<option value='Move Menu After'>Move Menu After</option>";
	echo "</optgroup>";
	echo "<optgroup label=\"Menu Deletion\">";
	echo "<option value='Delete Menu'>Delete Menu</option>";
	echo "</optgroup>";
	echo "<optgroup label=\"Exit Here\">";
	echo "<option value='Exit Edit Menus'>Exit Edit Menus</option>";
	echo "</optgroup>";
	echo "</select>";
}

This also adds selections and some decorations to group choices in the selects in such a way that is easy to grasp the function. The commands for edit menu are simple enough that I didn't feel the need to pass in the post, that may change.

Lovely, another bug in the previous post. Replace the first echo line in the function select_command() with echo "<select onchange='updateMenu();' name='command'>"; It doesn't seem to matter how long I look at this stuff, something is always wrong with the post. Here I missed part of the edit. I have multiple copies of the same code, the code that actually runs on my machine, and the 'neutered' code that will actually display on a web page rather than execute. I try to keep them "the same", but they aren't.

New Connect: program

The connect.php has been reworked a bit to accommodate auto-magical db and table creation. This involved dividing connect.php in twain adding a file called ~www/tutorial/include/sql_password.php which contains:

<?php
// this is an in-line and the only place where the db username
// and password should appear.
$db = "tutorial_db";
$link = mysql_connect('localhost', 'admin', 'password');
?>
And copy the following into ~www/tutorial/include/connect.php
<?php
// this is an in-line
$debug = false;
include "include/sql_password.php";
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
if($debug == true) {echo 'Connected to MySQL successfully<br>';}
mysql_select_db($db);
?>
There is a bit of a hazard here in the $debug = false; assignment. Since this is an include and not a function the variable $debug is in scope anywhere after you drop in the connect.php include. This means if you do something like this:
$debug = true;
include "include/connect.php";
You might think that $debug == true, but you would be wrong. You might want to remove debugging entirely from the connect but hang on for a bit. We want all the debugging turned on for the moment so we can see how the bits are flying. Maybe just removing the assign in the connect will get us what we want. The important thing here is to become aware of the scope of variables. This is covered in exquisite detail in the references I have previously pointed out. You need to know this, Buckaroo.

Now we want to replace the function check_tables() in ~www/tutorial/include/check_tables.php with:

function check_tables() {
// Usage without mysql_list_dbs() deprecated
	include 'include/sql_password.php'; // connects us to db
	if (!$link) {die('Could not connect: ' . mysql_error());}
	mysql_select_db($db);
	$debug = false;
	if($debug == true){echo 'In check_tables() Connected SQL link='.$link.'<br />';}
	$res = mysql_query("SHOW DATABASES");
	if($debug == true){echo "checking database...<br />";}
	$present = false;
	while ($row = mysql_fetch_assoc($res)) {
		if($debug == true){echo $row['Database']." ";}
		if($row['Database'] == $db){$present = true;}
	}
	if($debug == true){echo "<br />";}
	if($present == false) { // db not present, creat it.
		echo "Database ".$db." not present. Creating...<br />";
		$sql = 'CREATE DATABASE '.$db;
		if (mysql_query($sql, $link)) {
			echo "Database ".$db." created successfully<br />";
		} else {
			echo 'Error creating '.$db.': ' . mysql_error() . "<br />";
			die(mysql_error()); // die a horrible death, can't go on...
		}
	}
	mysql_select_db($db);
	$sql = "SHOW TABLES FROM ".$db;
	$result = mysql_query($sql);
	if (!$result) {
		echo "DB Error, could not list tables\n";
		echo 'MySQL Error: ' . mysql_error();
		exit; // die a horrible death, can't go on...
	}
	$items_present = false; // flags for table creation
	$item_menus_present = false;
	while ($row = mysql_fetch_row($result)) { // paw through the results
		if($debug == true){echo "Table: {$row[0]} <br />";}
		//echo "Table: ."$row[0]." ";
		if($row[0] == 'items') {$items_present = true;}
		if($row[0] == 'item_menus') {$item_menus_present = true;}
	}
	mysql_free_result($result); //return some memory
	if($items_present == false) { //make items table
		create_items_table();
	}
	if($item_menus_present == false) { //make item_menus table
		create_item_menus_table();
	}
}

The above code uses the new connect formula. The actual table creation stays the same. One of the things to notice is that the user will be informed whenever a db or table is created, no mater the state of $debug. Another thing is that if we fail to make the db or the table for some reason we die a horrible death. The screen goes blank and truth is hard to see. View Source is your friend at that point, it will often show you just where you went awry. echo Statements are useful too.

Edit Menu: program

Now we need to add the two new files. The first is edit_menu.php I am a bit torn about this. The object (noun) part of this is pretty small and the only really new elements are the function htmlspecialchars_decode() and the function select_generic() which is where we have been trying to get. The verb part though, I could have stripped out everything but the functionality of 'Add Menu', but then I'd have to put it right back in. Sigh.

Copy all of this into: ~www/tutorial/include/edit_menu.php

<?php 
/*	This function provides for the editing of the Item, Ingredient, and Meal
 * 	menus.
 * 	copyright 2011 by mumble all rights reserved
 *	file: edit_menu.php
 *	
 * 	2011/10/07 - initial working cut
 * 	2011/10/14 - update to current UI - working
* 	2012/02/21 - modified for tutorial - working
 * 
 * 	This function edits the menus created by the select_generic() objects which are used to 
 * 	look into the database.
*/

function edit_menu($_POST) 
{
	$New_menu = htmlspecialchars_decode($_POST["new_menu"]);
	$Current_menu = $_POST["menu_current"];
	$EM_command = $_POST["edit_menu_command"];
	$New_menu = htmlspecialchars_decode($_POST["new_menu"]);  // used in edit_menus as a source (is a textfield)
	
	$debug = false; if($debug) {echo "<br />In edit_menu() post_length=".count($_POST)."<br />";}	 	 
	if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br>";}} 	
		
	if ($Current_menu == '') {$Current_menu = '0';}

	// create a selector for which menu to edit
	// this probably ought to be a function but so far this is the
	// only time I have to do this one.
	echo "<select onchange='updateMenu()' name='menu_current'>";
	if($Current_menu == '0') {echo "<option selected='selected' value='0'>Items</option>";}
	else {echo "<option value='0'>Items</option>";}
	echo "</select>";
		if($Current_menu == '0') {select_generic('item',$_POST,'menu_only','_source');}
	echo "<input id='em_text' type='text' size='32' maxlength='64' value='".$New_menu."' name='new_menu'><br /> Destination: ";
		if($Current_menu == '0') {select_generic('item',$_POST,'menu_only','_destination');}
	echo "<br>Menu Commands: ";
	edit_menu_command();
	echo "<input id='em_exists' type='hidden' value='exists' name='edit_menu_exists'>";

}
// end of the function, the rest is included as the grammar of the function

// we begin with a little general housekeeping.
// set the value of the data bases being worked with
if ($Current_menu == '0') {$menu_db = 'item_menus';}

// before we actually try to execute any commands we see if the inputs are even vaguely reasonable.
if ($EM_command == 'Rename Menu' || $EM_command == 'Add Menu') {  // check for good inputs 
	if($New_menu == "") {
		$Error = "There must be text in the textfield to ".$EM_command; 
		$EM_command = "Menu Edit Commands"; // don't want to return here
	}
}
// fix up the global menu vars to point to the right menu set
if($Current_menu == '0') {$Menu_source = $_POST['item_menu_source'];$Menu_destination = $_POST['item_menu_destination'];}
/*
if($Current_menu == '1') {$Menu_source = $_POST['ingredient_menu_source'];$Menu_destination = $_POST['ingredient_menu_destination'];}
if($Current_menu == '2') {$Menu_source = $_POST['food_menu_source'];$Menu_destination = $_POST['food_menu_destination'];}
*/
//and now we should be ready to actually execute some commands

if ($EM_command == 'Rename Menu') {  // rename menu
	$debug = false;
	include 'include/connect.php';
	$query_str = "UPDATE ".$menu_db." SET name='".$New_menu."' WHERE index0='".$Menu_source."'";
	if($debug) {echo $query_str."<br>";}
	if(!$debug) {$result = mysql_query($query_str) or die(mysql_error());}
	if(!$debug) {$Feedback = "Menu: ".$Menu_source." named ".$New_menu." saved to DB.";}
	if($debug) {echo "Menu: ".$Menu_source." named ".$New_menu." NOT saved to DB.***debugging in edit_menu_rename***<br>";}
}

if ($EM_command == 'Add Menu') {  // add menu
	$debug = true;
	include 'include/connect.php';
	$query_str = "SELECT MAX(index0) as index0 FROM ".$menu_db."";
	if($debug) {echo $query_str."<br>";}
	// SELECT doesn't need a debug shield
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$new_index = $row['index0'] + 1 ;  // next new index
	if($debug) {echo "new index = ".$new_index."<br>";}
	$query_str = "INSERT INTO ".$menu_db." 
	(index0, name) 
	VALUES('".$new_index."', '".$New_menu."' )";
	if($debug) {echo $query_str."<br>";}
	if(!$debug) {$result = mysql_query($query_str) or die(mysql_error());}
	if(!$debug) {$Feedback = "Menu: ".$New_menu." at position ".$new_index." saved to DB.";}
	if($debug) {echo "Menu: ".$New_menu." at position ".$new_index." NOT saved to DB.***debugging in edit_menu_add***<br>";}
}

if ($EM_command == 'Delete Menu') {  // delete menu
	$debug = false;
	if($debug) {echo "Menu src = ".$Menu_source." Menu dst = ".$Menu_destination."<br>";}
	if ($Menu_source == $Menu_destination) { 
		$Error = "Source and Destination menus must be different.<br> Source menu contents get copied to the destination menu.<br> Delete Failed!</p><br>";
	} else {
		include 'include/connect.php';
		$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_source."'";
		if($debug) {echo $query_str."<br>";}
		// SELECT needs no debug shield
		$result = mysql_query($query_str) or die(mysql_error());
		$row = mysql_fetch_array( $result );
		$sname = $row['name'];  // source name
		$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_destination."'";
		$result = mysql_query($query_str) or die(mysql_error());
		$row = mysql_fetch_array( $result );
		$dname = $row['name'];  // destination name
		$query_str = "SELECT MAX(index0) as index0 FROM ".$menu_db."";
		$result = mysql_query($query_str) or die(mysql_error());
		$row = mysql_fetch_array( $result );
		$max_index = $row['index0'];  // biggest index before delete
		if($debug) {echo "max index = ".$max_index."<br>";}
		$query_str = "DELETE FROM ".$menu_db." WHERE index0='".$Menu_source."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		//echo "Menu: ".$sname." at position ".$Menu_source." deleted from DB.<br>";
		$Feedback = "Menu: ".$sname." at position ".$Menu_source." deleted from DB.<br>";
		$mv_index = $Menu_source;
		while ($mv_index <= $max_index) {
			//echo "working index = ".$mv_index." max = ".$max_index."<br>";
			$Feedback = "working index = ".$mv_index." max = ".$max_index."<br>";
			$query_str = "UPDATE ".$menu_db." SET index0='".$mv_index."' WHERE index0='".($mv_index + 1)."'";
			if($debug) {echo $query_str."<br>";}
			$result = mysql_query($query_str) or die(mysql_error());
			if($mv_index == $Menu_source) {
				//echo "Moving ".$thing_db."  on Menu ".$sname." to ".$dname."<br>";
				$Feedback = "Moving ".$thing_db."  on Menu ".$sname." to ".$dname."<br>";
				$query_str = "UPDATE ".$thing_db." SET menus='".$Menu_destination."' WHERE menus='".$Menu_source."'";
				if($debug) {echo $query_str."<br>";}
				$result = mysql_query($query_str) or die(mysql_error());
				//echo "".$thing_db."  moved from ".$sname." to ".$dname."<br>";
				$Feedback = "".$thing_db."  moved from ".$sname." to ".$dname."<br>";
			} else {
				echo "Adjusting menu ".$mv_index." in ".$thing_db."  db...<br>";
				$Feedback = "Adjusting menu ".$mv_index." in ".$thing_db."  db...<br>";
				$query_str = "UPDATE ".$thing_db."  SET menus='".($mv_index-1)."' WHERE menus='".$mv_index."'";
				if($debug) {echo $query_str."<br>";}
				$result = mysql_query($query_str) or die(mysql_error());
			}	
			$mv_index++;
		}
	}
}

if ($EM_command == 'Move Menu After') { // check for valid inputs to move after 
	$debug = false;
	//if($debug) {$ta = array_keys($_POST);for($ti=0;$ti<count($ta);$ti++) {echo $ta[$ti]."=".$_POST[$ta[$ti]]."<br>";}} 	
	if($debug) {echo "Menu_source = ".$Menu_source." Menu_destination = ".$Menu_destination."<br>";}
	include 'include/connect.php';
	$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_source."'";
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$sname = $row['name'];  // source name
	$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_destination."'";
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$dname = $row['name'];  // destination name
	if($Menu_source == $Menu_destination) { // 
		//echo "<p class='ex'>Can not move ".$sname." after ".$dname."</p><br>";
		$Error = "Move Menu After: Can not move ".$sname." after ".$dname." ";
		$EM_command = 'Menu Edit Commands'; // make command go away.
	}
}
if ($EM_command == 'Move Menu After') {  // move source menu after destination menu
	include 'include/connect.php';
	$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_source."'";
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$sname = $row['name'];  // source name
	$query_str = "SELECT name FROM ".$menu_db." WHERE index0='".$Menu_destination."'";
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$dname = $row['name'];  // destination name
	if($Menu_source == $Menu_destination) { // this should never execute
		//echo "<p class='ex'>Can not move ".$sname." after ".$dname."</p><br>";
		$Error = "Can not move ".$sname." after ".$dname." ";
		$EM_command = 'Menu Edit Commands'; // make command go away.
	}
	//echo "Moving menu item ".$sname." after ".$dname."<br>";
	$Feedback = "Moving menu item ".$sname." after ".$dname."<br>";
	// get the index one larger than is being used for temporary storage
	$query_str = "SELECT MAX(index0) as index0 FROM ".$menu_db."";
	$result = mysql_query($query_str) or die(mysql_error());
	$row = mysql_fetch_array( $result );
	$max_index = $row['index0'];  // biggest index 
	if($debug) {echo "max index = ".$max_index."<br>";}
	$mv_index = $Menu_source;
	if($debug) {echo "working index = ".$mv_index." max = ".$max_index."<br>";}

	if($Menu_source > $Menu_destination) { //moving source up, do this
		// move source to max+1  
		$query_str = "UPDATE ".$menu_db." SET index0='".($max_index + 1)."' WHERE index0='".($mv_index)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		$query_str = "UPDATE ".$thing_db."  SET menus='".($max_index + 1)."' WHERE menus='".($mv_index)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		
		// shift everyone from source-1 to dest up one
		for($mv_index = $Menu_source-1; $mv_index > $Menu_destination; $mv_index--) {
			$query_str = "UPDATE ".$menu_db." SET index0='".($mv_index+1)."' WHERE index0='".($mv_index)."'";
			if($debug) {echo $query_str."<br>";}
			$result = mysql_query($query_str) or die(mysql_error());
			$query_str = "UPDATE ".$thing_db."  SET menus='".($mv_index+1)."' WHERE menus='".($mv_index)."'";
			if($debug) {echo $query_str."<br>";}
			$result = mysql_query($query_str) or die(mysql_error());
		}
		// move max+1 to dest+1
		$query_str = "UPDATE ".$menu_db." SET index0='".($Menu_destination + 1)."' WHERE index0='".($max_index + 1)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		$query_str = "UPDATE ".$thing_db."  SET menus='".($Menu_destination + 1)."' WHERE menus='".($max_index + 1)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
	} else {  // Moving src down the menu, do this
		// move source to max+1  
		$query_str = "UPDATE ".$menu_db." SET index0='".($max_index + 1)."' WHERE index0='".($mv_index)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		$query_str = "UPDATE ".$thing_db."  SET menus='".($max_index + 1)."' WHERE menus='".($mv_index)."'";
		if($debug) {echo $query_str."<br>";}	
		$result = mysql_query($query_str) or die(mysql_error());
		
		// shift everyone from source+1 to dest up one
		for($mv_index = $Menu_source+1; $mv_index <= $Menu_destination; $mv_index++) {
			$query_str = "UPDATE ".$menu_db." SET index0='".($mv_index-1)."' WHERE index0='".($mv_index)."'";
			if($debug) {echo $query_str."<br>";}
			$result = mysql_query($query_str) or die(mysql_error());
			$query_str = "UPDATE ".$thing_db."  SET menus='".($mv_index-1)."' WHERE menus='".($mv_index)."'";
			if($debug) {echo $query_str."<br>";}
			$result = mysql_query($query_str) or die(mysql_error());
		}
		// move max+1 to dest
		$query_str = "UPDATE ".$menu_db." SET index0='".($Menu_destination)."' WHERE index0='".($max_index + 1)."'";
		if($debug) {echo $query_str."<br>";}
		$result = mysql_query($query_str) or die(mysql_error());
		$query_str = "UPDATE ".$thing_db."  SET menus='".($Menu_destination)."' WHERE menus='".($max_index + 1)."'";
		if($debug) {echo $query_str."<br>";}	
		$result = mysql_query($query_str) or die(mysql_error());
	}
}
	
?>
This is an interesting file. A lot of the complexity of the verb part has to do with deleting menus (the items need to be moved to a destination menu) and changing the ordering of menus. I chose to order the menus by the value of index0 which implies that as the index0 for a particular menu item, say 'dairy' changes from 4 to 0 to put it at the top of the menu, then all of the items that reference the menus pointed to by 0 or 4 need to be reworked. This is probably not so great. We really need probably yet another table that actually keeps the ordering. We'll try to remember to fix this.

Select Generic: program

Now we get to the good part. This next function builds a select that uses two tables in a database. The first table, mumble needs to have a primary key called 'name' or if the $base_name == 'item' then it is called 'upc'. This table holds the data, or collection of information. The second table, mumble_menu has a much smaller bit of data that helps us organize the first table. You can point this select at any pair of tables that are organized like this, and we do.

The function requires $base_name, $_POST, $mode and $postfix = "". The mode switches the select between 'menu_only' which just shows the categories available in the collection, or not, which shows the categories and the data in two adjacent selects. The postfix part we use to differentiate separate instances of the same function and we set that to nothing as the default case.

And finally ~www/tutorial/include/select_generic.php

<?php
/*		
*		file: include/select_generic.php
*		
*		
*		2011/10/05 - working initial cut
*		2012/02/21 - fixed hang on empty table
*		
*		This function is a template for a select object that provides a single level of
* 		menu selection to a collection of objects.  The menus are stored in the table $base_name_menus
* 		and the collection is in $base_name.  A $postfix is available to further differentiate
* 		select objects that reference the same db but need to have different names. $mode is
* 		used to get the menu only without the collection.
* 
* 		
*/
function select_generic($base_name, $_POST, $mode, $postfix = "") //$Menu, $Upc, $select_menu_id, $select_item_id, $mode, $menu_name
{
	if($base_name == 'item') {$generic_key_name = 'upc';}
	else {$generic_key_name = 'name';}  // base names 'ingredient', 'food'
	
	$Menu = $_POST[$base_name.'_menu'.$postfix];	// integer index into the menu
	$IndexX = $_POST[$base_name.'_name'.$postfix];  // $Ucp or name depending on table, PRIMARY key
	
	if( $Menu == "") {$Menu = 0;} // if not initialized, point somewhere reasonable
	
	if($mode != 'menu_only') { 
		echo "<select onchange='validateUPC();'  id='".$base_name."_menu_id".$postfix."'  name='".$base_name."_menu".$postfix."' >";
	} else {
		echo "<select onchange='updateMenu();'  id='".$base_name."_menu_id".$postfix."'  name='".$base_name."_menu".$postfix."' >";
		echo "<optgroup label='".str_replace('_',' ',$base_name.$postfix)."'>";// decoration for menu only, lets us distinguish menus
	}
	
	include 'include/connect.php';
	// check to see that there are entries in the table.
	
	// Get all the data from the "item_menus" table
	$result = mysql_query("SELECT * FROM ".$base_name."_menus ORDER BY index0") 
		or die("getting item_menus table ".mysql_error());  
	
	while($row = mysql_fetch_array( $result )) {
		// Print out the contents of each row into a table
		if ($row['index0'] != $Menu) {
			echo "<option value='".$row['index0']."'>".htmlspecialchars_decode($row['name'],ENT_QUOTES)."</option>";
		} else {
			echo "<option selected='selected' value='".htmlspecialchars_decode($row['index0'],ENT_QUOTES)."'>".$row['name']."</option>";	
		}
	} 
	if($mode == 'menu_only') { echo "</optgroup>";} // decoration for menu only
	mysql_close($link);
	echo "</select>";
	if($mode != 'menu_only') { 
		echo "<select onchange='updateMenu();' id='".$base_name."_select_id".$postfix."'   name='".$base_name."_name".$postfix."'>";
		include 'include/connect.php';
		// Get all the data from the "items" table
		$result = mysql_query("SELECT * FROM ".$base_name."s WHERE menus=".$Menu." ORDER BY name") 
			or die(mysql_error());
		while($row = mysql_fetch_array( $result )) {
			// Print out the contents of each row into a table
			if ($row[$generic_key_name] != $IndexX){
				echo "<option value=\"".$row[$generic_key_name]."\">".htmlspecialchars_decode($row['name'],ENT_QUOTES)."</option>";
			} else {
				echo "<option selected=\"selected\" value=\"".$row[$generic_key_name]."\">".htmlspecialchars_decode($row['name'],ENT_QUOTES)."</option>";	
			}
		} 
		mysql_close($link);
		echo "</select>";
	}
}
?>
This should all work out of the box just so long and you don't do anything but 'Add Menu'. With the new programmatic creation of the db and tables I haven't bullet-proofed edit_menu() with respect to moving and deleting menu items when there are no items in the collection. So, you can break the tables if you do anything other than Add Menu. If you do break the tables, and I hope you do, simply delete them with phpMyAdmin and submit the form again to recreate the empty tables. Get very familiar with phpMyAdmin, it too is a wonderful debugging tool.

Have Fun.

Edit Items: program

Here is a nice dataset for our database. I've done the typing already so there is no reason for you to do it. Besides, it's an excuse to exercise our phpMyAdmin skills. So poke at: db download and put it someplace you will remember. Open phpMyAdmin and select tutorial_db then Structure. Empty the tables. The tables need to exist and be empty for the next part to work. Import the file tutorial_db.xml.zip. Scroll down and click Go. This should complete successfully and give you 147 items and 13 item_menus. This is much easier than typing.

You might want to look at the file in the download. It is in our old friend XML and completely human readable. After the first few entries it gets pretty boring.

Stuff the following in index.php in the appropriate spot. With the code you have, if you have imported the database data above, you should see your command select and then a generic select pointed at the db. Fiddle with it. There is a bug that you need to understand.

	select_command($_POST); // construct global commands
	check_tables(); // check to see that tables present
	select_generic('item',$_POST,'all'); // we need tables for this to work.
	echo "<br />";
You should see:

JavaScript for real:

You should see an irritating slidebox pop out of the right side about now. This is produced by JavaScript when the browser exposes to view the paragraph with id='last'. Two external scripts are used for this. include/jquery.min.js and include/modernizr-1.5.min.js. The advantage of using external scripts is to simplify and reuse code. The disadvantage is that this technique doesn't allow the packaging of the entire page into a self contained file.

Another Annoying Trick

The JavaScript provides the animation part, moving the slidebox. Motion of elements isn't part of HTML (nor should it be). It takes two scripts to do this because Microsoft works hard to split any standard that exists. Reading code it seems that there are two ways to do everything, the right way and the Microsoft way.

Johannes Dei gratia rex Anglie, dominus Hibernie, dux Normannie et Aquitannie, et comes Andegavie, archiepiscopis, episcopis, abbatibus, comitibus, baronibus, justiciariis, forestariis, vicecomitibus, prepositis, ministris et omnibus ballivis et fidelibus suis salutem.

Sciatis nos intuitu Dei et pro salute anime nostre et omnium antecessorum et heredum nostrorum, ad honorem Dei et exaltationem sancte Ecclesie, et emendacionem regni nostri, per consilium venerabilium patrum nostrorum, Stephani Cantuariensis archiepiscopi tocius Anglie primatis et sancte Romane ecclesie cardinalis, Henrici Dublinensis archiepiscopi, Willelmi Londoniensis, Petri Wintoniensis, Joscelini Bathoniensis et Glastoniensis, Hugonis Lincolniensis, Walteri Wygorniensis, Willelmi Coventriensis, et Benedicti Roffensis episcoporum; magistri Pandulfi domini pape subdiaconi et familiaris, fratris Aymerici magistri milicie Templi in Anglia; et nobilium virorum Willelmi Mariscalli comitis Penbrocie, Willelmi comitis Sarresburie, Willelmi comitis Warennie, Willelmi comitis Arundellie, Alani de Galeweya constabularii Scocie, Warini filii Geroldi, Petri filii Hereberti, Huberti de Burgo senescalli Pictavie, Hugonis de Nevilla, Mathei filii Hereberti, Thome Basset, Alani Basset, Philippi de Albiniaco, Roberti de Roppeleia, Johannis Mariscalli, Johannis filii Hugonis et aliorum fidelium nostrorum.

John, by the grace of God, king of England, lord of Ireland, duke of Normandy and Aquitaine, and count of Anjou, to the archbishops, bishops, abbots, earls, barons, justiciars, foresters, sheriffs, stewards, servants, and to all his bailiffs and liege subjects, greeting.

Know that, having regard to God and for the salvation of our souls, and those of all our ancestors and heirs, and unto the honour of God and the advancement of holy Church, and for the reform of our realm, [we have granted as underwritten]1 by advice of our venerable fathers, Stephen, archbishop of Canterbury, primate of all England and cardinal of the holy Roman Church, Henry archbishop of Dublin, William of London, Peter of Winchester, Jocelyn of Bath and Glastonbury, Hugh of Lincoln, Walter of Worcester, William of Coventry, Benedict of Rochester, bishops; of master Pandulf, subdeacon and member of the household of our lord the Pope, of brother Aymeric (master of the Knights of the Temple in England), and of the illustrious men2 William Marshal, earl of Pembroke, William, earl of Salisbury, William, earl Warenne, William, earl of Arundel, Alan of Galloway (constable of Scotland), Waren Fitz Gerald, Peter Fitz Herbert, Hubert de Burgh (seneschal of Poitou), Hugh de Neville, Matthew Fitz Herbert, Thomas Basset, Alan Basset, Philip d’Aubigny, Robert of Roppesley, John Marshal, John Fitz Hugh, and others, our liegemen.

That's all folks!

I am nerdier than 98% of all people. Are you a nerd? Click here to take the Nerd Test, get nerdy images and jokes, and talk on the nerd forum!

NerdTests.com says I'm a Slightly Dorky Nerd God.  Click here to take the Nerd Test, get geeky images and jokes, and write on the nerd forum!

"Who are the militia? Are they not ourselves? Is it feared, then, that we shall turn our arms each man gainst his own bosom. Congress have no power to disarm the militia. Their swords, and every other terrible implement of the soldier, are the birthright of an American...[T]he unlimited power of the sword is not in the hands of either the federal or state governments, but, where I trust in God it will ever remain, in the hands of the people."
- Tenche Coxe, founding father & dead white guy.

Is that gun safe?
Is gun. Is not safe.

Part of my modest contribution to Western Civilization...

Text Copyright © 2012 by Stephen Jackson