• Content count

  • Joined

  • Last visited

Everything posted by iwato

  1. BACKGROUND: Please find below a portion of a PHP class used to create an RSS feed. Included are only the constructor function and the function used to create the actual document. All other functions have been omitted so as to focus on the question at hand. My reason for posting this code is to better understand the proper way to create a class. As you can readily see from the __construct( ) function of this class each new instance of the class requires six parameter values. Although the author lists these parameters at the beginning of the class definition, he comments them out, rather than initializing them. QUESTION: Is this standard practice? What is to be gained by not declaring them outside of the __construct( ) function? It appears to create an unnecessary repetitious use of the pseudo $this variable. <?php /** * rss_feed (simple rss 2.0 feed creator php class) * * @author Christos Pontikis http://pontikis.net * @copyright Christos Pontikis * @license MIT http://opensource.org/licenses/MIT * @version 0.1.0 (28 July 2013) * */ class rss_feed { /** * Constructor * * @param array $a_db database settings * @param string $xmlns XML namespace * @param array $a_channel channel properties * @param string $site_url the URL of your site * @param string $site_name the name of your site * @param bool $full_feed flag for full feed (all topic content) */ public function __construct($a_db, $xmlns, $a_channel, $site_url, $site_name, $full_feed = false) { // initialize $this->db_settings = $a_db; $this->xmlns = ($xmlns ? ' ' . $xmlns : ''); $this->channel_properties = $a_channel; $this->site_url = $site_url; $this->site_name = $site_name; $this->full_feed = $full_feed; } /** * Generate RSS 2.0 feed * * @return string RSS 2.0 xml */ public function create_feed() { $xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n"; $xml .= '<rss version="2.0"' . $this->xmlns . '>' . "\n"; // channel required properties $xml .= '<channel>' . "\n"; $xml .= '<title>' . $this->channel_properties["title"] . '</title>' . "\n"; $xml .= '<link>' . $this->channel_properties["link"] . '</link>' . "\n"; $xml .= '<description>' . $this->channel_properties["description"] . '</description>' . "\n"; // channel optional properties if(array_key_exists("language", $this->channel_properties)) { $xml .= '<language>' . $this->channel_properties["language"] . '</language>' . "\n"; } if(array_key_exists("image_title", $this->channel_properties)) { $xml .= '<image>' . "\n"; $xml .= '<title>' . $this->channel_properties["image_title"] . '</title>' . "\n"; $xml .= '<link>' . $this->channel_properties["image_link"] . '</link>' . "\n"; $xml .= '<url>' . $this->channel_properties["image_url"] . '</url>' . "\n"; $xml .= '</image>' . "\n"; } // get RSS channel items $now = date("YmdHis"); // get current time // configure appropriately to your environment $rss_items = $this->get_feed_items($now); foreach($rss_items as $rss_item) { $xml .= '<item>' . "\n"; $xml .= '<title>' . $rss_item['title'] . '</title>' . "\n"; $xml .= '<link>' . $rss_item['link'] . '</link>' . "\n"; $xml .= '<description>' . $rss_item['description'] . '</description>' . "\n"; $xml .= '<pubDate>' . $rss_item['pubDate'] . '</pubDate>' . "\n"; $xml .= '<category>' . $rss_item['category'] . '</category>' . "\n"; $xml .= '<source>' . $rss_item['source'] . '</source>' . "\n"; if($this->full_feed) { $xml .= '<content:encoded>' . $rss_item['content'] . '</content:encoded>' . "\n"; } $xml .= '</item>' . "\n"; } $xml .= '</channel>'; $xml .= '</rss>'; return $xml; } } ?>
  2. Oops! I thought someone would know this, so that I could avoid the experimentation. Roddy
  3. The method is there. Simply I left it out, so as not to cause unnecessary clutter. Maybe I have misunderstood the use of the constructor function. Until now I was under the impression that once the values of a constructor function's parameters are assigned to the declared properties via the $this->declared_property mechanism, they can be readily accessed in other methods of the class simply by inserting their respective variable names. By way of example consider the following line of code taken from the create_feed( ) method. $xml .= '<title>' . $this->channel_properties["title"] . '</title>' . "\n"; Had the property $channel_properties been properly declared at the outset of the class definition, then its elements and their respective values could have been directly accessed from within the create_feed( ) and other class methods without having to make use of the pseudo $this variable and the arrow operator? In other words, rather than writing the above the author could simply have written $xml .= '<title>' . $channel_properties["title"] . '</title>' . "\n"; Am I in error in this regard? Roddy
  4. Thank you for your continued clarification. Now, had the properties been declared, as you have just done, would it have been necessary for the author to use the arrow operator in the second function as well? I am referring in particular to the function called create_feed( ). As I mentioned in my original post, it appears to me that by not declaring the variables at the beginning of the class, the author has compelled an inordinate use of the arrow operator. Is this not true? Or, have I misunderstood? Roddy
  5. I regret not having asked this question sooner, but when you do not know anything, you have to begin by believing in something. Then, try it out, and see if it works. The DOMDocument class does appear to be a good deal more solid, and I will certainly make use of it in the future. Already I have included it in my notes. For the moment I do not have time to familiarize myself with an entirely new PHP class, and would be very happy, if I could simply improve upon what I already know within the indicated class. I do not wish to be a bad student, but need to begin earning money quickly, else there will be nothing to support my further study and implementation. I am dangling on a financial thread that is wearing down both my spirit and health. Please be understanding. Returning to the original question, however, I agree that the author has listed the function's parameters, and we appear to agree that he should have first declared these parameters as class properties. What then would have been the proper way to reference the properties' values in the appended strings to the $xml variable? Roddy
  6. I recently downloaded the following PHP include and discovered an entire method of coding that I do not understand. Could someone please explain the use of the following, for me non-standard, characters in this document: - + @@ ... @@ Is this a way of designating the codes of different versions within the same script? Is it functional or is it comment? How does it work? --- feedcreator.class.php Mon Oct 11 20:12:36 2004 +++ feedcreator-ppt.class.php Mon Nov 21 18:58:50 2005 @@ -1,12 +1,14 @@ <?php /*************************************************************************** -FeedCreator class v1.7.2 +FeedCreator class v1.7.2-ppt originally (c) Kai Blankenhorn www.bitfolge.de kaib@bitfolge.de v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn v1.5 OPML support by Dirk Clemens +v1.7.2-mod on-the-fly feed generation by Fabian Wolf (info@f2w.de) +v1.7.2-ppt ATOM 1.0 support by Mohammad Hafiz bin Ismail (mypapit@gmail.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -27,6 +29,14 @@ Changelog: +v1.7.2-ppt 11-21-05 + added Atom 1.0 support + added enclosure support for RSS 2.0/ATOM 1.0 + added docs for v1.7.2-ppt only! + +v1.7.2-mod 03-12-05 + added output function outputFeed for on-the-fly feed generation + v1.7.2 10-11-04 license changed to LGPL @@ -138,6 +148,14 @@ //optional item->descriptionTruncSize = 500; item->descriptionHtmlSyndicated = true; + + //optional (enclosure) + $item->enclosure = new EnclosureItem(); + $item->enclosure->url='http://http://www.dailyphp.net/media/voice.mp3'; + $item->enclosure->length="950230"; + $item->enclosure->type='audio/x-mpeg' + + $item->date = $data->newsdate; $item->source = "http://www.dailyphp.net"; @@ -147,9 +165,12 @@ } // valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), -// MBOX, OPML, ATOM, ATOM0.3, HTML, JS +// MBOX, OPML, ATOM, ATOM10, ATOM0.3, HTML, JS echo $rss->saveFeed("RSS1.0", "news/feed.xml"); +//to generate "on-the-fly" +$rss->outputFeed("RSS1.0"); + *************************************************************************** * A little setup * @@ -164,7 +185,8 @@ /** * Version string. **/ -define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); + +define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2-ppt (info@mypapit.net)"); @@ -201,6 +223,17 @@ var $date; /** + * Add <enclosure> element tag RSS 2.0 + * modified by : Mohammad Hafiz bin Ismail (mypapit@gmail.com) + * + * + * display : + * <enclosure length="17691" url="http://something.com/picture.jpg" type="image/jpeg" /> + * + */ + var $enclosure; + + /** * Any additional elements to include as an assiciated array. All $key => $value pairs * will be included unencoded in the feed item in the form * <$key>$value</$key> @@ -214,6 +247,26 @@ // var $source; } +class EnclosureItem extends HtmlDescribable { + /* + * + * core variables + * + **/ + var $url,$length,$type; + + /* + * For use with another extension like Yahoo mRSS + * Warning : + * These variables might not show up in + * later release / not finalize yet! + * + */ + var $width, $height, $title, $description, $keywords, $thumburl; + + var $additionalElements = Array(); + +} /** @@ -265,6 +318,7 @@ } + /** * An FeedHtmlField describes and generates * a feed, item or image html field (probably a description). Output is @@ -333,6 +387,63 @@ class UniversalFeedCreator extends FeedCreator { var $_feed; + function _setMIME($format) { + switch (strtoupper($format)) { + + case "2.0": + // fall through + case "RSS2.0": + header('Content-type: text/xml', true); + break; + + case "1.0": + // fall through + case "RSS1.0": + header('Content-type: text/xml', true); + break; + + case "PIE0.1": + header('Content-type: text/xml', true); + break; + + case "MBOX": + header('Content-type: text/plain', true); + break; + + case "OPML": + header('Content-type: text/xml', true); + break; + + case "ATOM": + // fall through: always the latest ATOM version + case "ATOM1.0": + header('Content-type: application/xml', true); + break; + + case "ATOM0.3": + header('Content-type: application/xml', true); + break; + + + case "HTML": + header('Content-type: text/html', true); + break; + + case "JS": + // fall through + case "JAVASCRIPT": + header('Content-type: text/javascript', true); + break; + + default: + case "0.91": + // fall through + case "RSS0.91": + header('Content-type: text/xml', true); + break; + } + } + function _setFormat($format) { switch (strtoupper($format)) { @@ -368,11 +479,15 @@ case "ATOM": // fall through: always the latest ATOM version + case "ATOM1.0": + $this->_feed = new AtomCreator10(); + break; + case "ATOM0.3": $this->_feed = new AtomCreator03(); break; - + case "HTML": $this->_feed = new HTMLCreator(); break; @@ -445,6 +560,20 @@ $this->_feed->useCached($filename, $timeout); } + + /** + * Outputs feed to the browser - needed for on-the-fly feed generation (like it is done in WordPress, etc.) + * + * @param format string format the feed should comply to. Valid values are: + * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". + */ + function outputFeed($format='RSS0.91') { + $this->_setFormat($format); + $this->_setMIME($format); + $this->_feed->outputFeed(); + } + + } @@ -692,6 +821,17 @@ echo "<br /><b>Error creating feed file, please check write permissions.</b><br />"; } } + + /** + * Outputs this feed directly to the browser - for on-the-fly feed generation + * @since 1.7.2-mod + * + * still missing: proper header output - currently you have to add it manually + */ + function outputFeed() { + echo $this->createFeed(); + } + } @@ -711,7 +851,7 @@ function FeedDate($dateString="") { if ($dateString=="") $dateString = date("r"); - if (is_integer($dateString)) { + if (is_numeric($dateString)) { $this->unix = $dateString; return; } @@ -770,7 +910,7 @@ /** * Gets the date stored in this FeedDate as an ISO 8601 date. * - * @return a date in ISO 8601 format + * @return a date in ISO 8601 (RFC 3339) format */ function iso8601() { $date = gmdate("Y-m-d\TH:i:sO",$this->unix); @@ -779,6 +919,7 @@ return $date; } + /** * Gets the date stored in this FeedDate as unix time stamp. * @@ -997,8 +1138,23 @@ $feed.= " <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n"; } $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + + if ($this->RSSVersion == "2.0" && $this->items[$i]->enclosure != NULL) + { + $feed.= " <enclosure url=\""; + $feed.= $this->items[$i]->enclosure->url; + $feed.= "\" length=\""; + $feed.= $this->items[$i]->enclosure->length; + $feed.= "\" type=\""; + $feed.= $this->items[$i]->enclosure->type; + $feed.= "\"/>\n"; + } + + + $feed.= " </item>\n"; } + $feed.= " </channel>\n"; $feed.= "</rss>\n"; return $feed; @@ -1072,7 +1228,88 @@ } } +/** + * AtomCreator10 is a FeedCreator that implements the atom specification, + * as in http://www.atomenabled.org/developers/syndication/atom-format-spec.php + * Please note that just by using AtomCreator10 you won't automatically + * produce valid atom files. For example, you have to specify either an editor + * for the feed or an author for every single feed item. + * + * Some elements have not been implemented yet. These are (incomplete list): + * author URL, item author's email and URL, item contents, alternate links, + * other link content types than text/html. Some of them may be created with + * AtomCreator10::additionalElements. + * + * @see FeedCreator#additionalElements + * @since 1.7.2-mod (modified) + * @author Mohammad Hafiz Ismail (mypapit@gmail.com) + */ + class AtomCreator10 extends FeedCreator { + + function AtomCreator10() { + $this->contentType = "application/atom+xml"; + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "<feed xmlns=\"http://www.w3.org/2005/Atom\""; + if ($this->language!="") { + $feed.= " xml:lang=\"".$this->language."\""; + } + $feed.= ">\n"; + $feed.= " <title>".htmlspecialchars($this->title)."</title>\n"; + $feed.= " <subtitle>".htmlspecialchars($this->description)."</subtitle>\n"; + $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n"; + $feed.= " <id>".htmlspecialchars($this->link)."</id>\n"; + $now = new FeedDate(); + $feed.= " <updated>".htmlspecialchars($now->iso8601())."</updated>\n"; + if ($this->editor!="") { + $feed.= " <author>\n"; + $feed.= " <name>".$this->editor."</name>\n"; + if ($this->editorEmail!="") { + $feed.= " <email>".$this->editorEmail."</email>\n"; + } + $feed.= " </author>\n"; + } + $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n"; + $feed.= "<link rel=\"self\" type=\"application/atom+xml\" href=\"". $this->syndicationURL . "\" />\n"; + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <entry>\n"; + $feed.= " <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n"; + $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n"; + if ($this->items[$i]->date=="") { + $this->items[$i]->date = time(); + } + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " <published>".htmlspecialchars($itemDate->iso8601())."</published>\n"; + $feed.= " <updated>".htmlspecialchars($itemDate->iso8601())."</updated>\n"; + $feed.= " <id>".htmlspecialchars($this->items[$i]->link)."</id>\n"; + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + if ($this->items[$i]->author!="") { + $feed.= " <author>\n"; + $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n"; + $feed.= " </author>\n"; + } + if ($this->items[$i]->description!="") { + $feed.= " <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n"; + } + if ($this->items[$i]->enclosure != NULL) { + $feed.=" <link rel=\"enclosure\" href=\"". $this->items[$i]->enclosure->url ."\" type=\"". $this->items[$i]->enclosure->type."\" length=\"". $this->items[$i]->enclosure->length . "\" />\n"; + } + $feed.= " </entry>\n"; + } + $feed.= "</feed>\n"; + return $feed; + } + +} + + /** * AtomCreator03 is a FeedCreator that implements the atom specification, * as in http://www.intertwingly.net/wiki/pie/FrontPage.
  7. Got it. Thanks for the introduction to Zend_Db. Something to investigate further on.
  8. BACKGROUND: I am in the process of creating two data collections: one will contain an eventually long series of weekly newsletters, and the other a similarly long series of weekly podcasts. Each week the newsletter will be sent out to newsletter subscribers and the creation of a new podcast will be announced. in contrast to the newsletters whose access will be unlimited to both subscribers and non-subscribers, the podcasts will be made available only to subscribers past a not yet determined number of weeks. I have not yet decided whether to produce separate newsfeeds (RSS/RFD/ATOM) for the newsletters and podcasts or only one newsfeed for the newsletter. QUESTION ONE: Is it possible to produce a single feed that provides access to separate folders of content? QUESTION TWO: Typically feeds refer to content that is readily accessible each time new material is made available. How does one typically go about making accessible only the most recent addition to a folder while controlling who does and not have access to the other members of the folder.
  9. OK. I would like to thank you for your help. I believe that I understand enough now to know where to take up the problem again once I have completed the RSS feed. By the way, I just learned from my host server that Apache is the webserver application employed, but that PHP files are parsed using suPHP rather than PHP. I suppose that this is also fairly common for servers who host a large number of accounts with everyone wanting control of his or her own ability to script in PHP. Have a great evening! Roddy
  10. BACKGROUND: I am in the process of creating two data collections: one will contain an eventually long series of weekly newsletters, and the other a similarly long series of weekly podcasts. Each week the newsletter will be sent out to newsletter subscribers and the creation of a new podcast will be announced. in contrast to the newsletters whose access will be unlimited to both subscribers and non-subscribers, the podcasts will be made available only to subscribers past a not yet determined number of weeks. I have not yet decided whether to produce separate newsfeeds (RSS/RFD/ATOM) for the newsletters and podcasts or only one newsfeed for the newsletter. In light of the aforementioned scenario I would like to know How does one typically limit access to the contents of a folder? Roddy
  11. I work with PHP and MySQL. Would it be better to approach the problem from the PHP side using MySQLi or from the SQL side? I am more comfortable with PHP, but am learning how to write SQL statements as I go along. Roddy
  12. Yes, this is the goal. I am not there yet. Any suggestions with regard to software would be helpful. I am at the exploration stage. Roddy
  13. JSG: It sounds like you need a database to manage the items in the feed, including posting dates, and also authorization for users that you can use to determine who has access to what. RAS: This question had more to do with the production of the XML file, but your response has told me how to resolve the problem, if I insist on separate folders for each issue and combination of newsletter and podcast. In the meantime, I have pretty much decided to store the two sets of content in separate folders and unite their elements as needed with a script. JSG: It sounds like you need a database to manage the items in the feed, including posting dates, and also authorization for users that you can use to determine who has access to what. RAS: Yes and No. Yes, I will use a MySQL data base to store the information that facilitates the handling of the content, but the content itself will be stored in folders. After some exploration on the net I discovered that using data bases to store media content for which access needs to be immediate and frequent -- protected or unprotected -- is simply inefficient. The database slows down the process of retrieval by a significant amount. In the end it appears that it is better to store media files in folders unless they are to be archived and only infrequently accessed.
  14. JSG: What does this have to do with XML? RAS: I am using PHP to create the XML file for my RSS feed. The PHP code reads the contents of the folder and from these contents produces a list of editable <item> tags as well as the parent <channel> tag. As the, thus produced, XML file resides in the same folder as the contents that it summarizes, and as PHP must read the contents of this folder, I must have access to all of the items in the folder. As it is the contents of this folder to which I wish to limit user access, it is important that I am well able to control access to both the folder and its contents in a variety of ways. JSG: On the server, you can configure a directory to require authentication, but that's the most basic kind where the browsers pops up a built-in box for username and password. RAS: This sort of folder access is not what I have in mind. JSG: You can also configure the server to pass all requests through a server-side script (using htaccess or URL rewriting in IIS), where the script would check for a login session prior to sending the requested file. RAS: I did a little research on the net and discovered that IIS is likely not a UNIX procedure. My remote host server uses LINUX, and my local test server uses Apache. JSG: You could also store the folder outside of the publicly accessible web directory and again use a server-side script to control access to the files. Those scripts can get a little tricky with modern browsers though, because you need to account for compression if the browser is asking for it and, importantly, support for partial requests. The browser may send one request just to check the file size and then send other requests for parts of the file. That's how streaming works in the browser, it will request only pieces of the file in case you skip to another part of a video or audio recording. RAS: Although the contents of the folder to which I have drawn your immediate attention will contain only podcasts (audio files) do you think the aforementioned reserverations will still be a concern? Certainly, I will want that the podcasts to be streamable, I have not yet decided to make them downloadable as well. Moving quickly ahead to the future, however, I expect to be hosting a folder of webinars as well. As I have yet to consult with my remote host about its streaming capacity or my access to it. Can you recommend a PHP class that might be useful in this regard? JSG: You may also be able to find a way to have the web server authenticate with PHP or another language before serving the file, which would save you the hassle of creating the script to handle the request. RAS: Could you please elaborate on this point? Roddy
  15. Ingolme: The absolute positioning is necessary -- unless you can show me a better method -- to insure that the height of the background element maintains a consistent portion to its responsive width.
  16. is there a better online resource to test responsive design modeling than the Safari browser's RD option?
  17. The text overlaps. What should appear in the footer separate and distinct from the main content appears in the main content. Rather than shrinking proportionally as appears in the Safari emulator, or expanding in scrolled overflow as in the Firefox emulator, the device browser tries to fit everything in the same viewport with no adjustment for size or proportionment. The proportional distances that I use for the CSS top and bottom properties appear to work fine in the emulator. Unfortunately, they appear to fail in the device itself. I tried the Firefox emulator at your suggestion, but it produced a rendering different from that produced by the Safari emulator. The worst of it, however, is that both emulators produce something different from what I see in my device. I now have three versions only one of which appears as it should and does in a normal browser environment on my iMac. Roddy
  18. Hi, Ingolme! In answer to your question: what appears in the tool does not appear in my iPhone. You can try it on your phone and browser, if you like. Here is the link. You will probably receive a fairly accurate rendering in your computer's browser viewport, as both Safari and Firefox render identical images for me. This is not what is viewed in my iPhone 4SE , though -- this, despite its appearing the same in the Safari emulator. Roddy
  19. After you have backed up your file change the parameters of the range function from 1,3 to 2,2, and eliminate the div tag containing the information for the individual whom you want to remove.
  20. How are you using your images? What is the purpose of their display? Do you understand Javascript and jQuery. I have found Colorbox (a jQuery plug-in) to be very useful. It is client-side. Roddy p.s. No offense implied to the server-side PHP forum! :-)
  21. Got it. I understand. Write the HTML into the document manually, and then alter the element with PHP according to what appears in &non_matches. Thanks!
  22. BACKGROUND: I am tempted to write something like the following foreach ($non-matches as $key => $val) { echo '<script> $("#' . $key . '").append("<p style=' . '"color:red;">Complete this item!</p>);</script>)'; } QUESTION ONE: Under the assumption that the echo statement is correct would you recommend this as proper programming procedure? If not, please explain why and provide an alternative, more appropriate strategy that would achieve the same objective suggested by the use of a jQuery object ? QUESTION TWO: If it is proper programming procedure, please correct the echo statement so that it will achieve the following: $("#...").append("<p style='color:red;'>Complete this item!</p>"); EDIT: In order to assist you in your response, the PHP variable $non-matches contains a list of values for the id attributes of form input control tags that have been carefully selected through a prior PHP procedure. An alternative approach that is currently under consideration is to create a JSON object, assign it to a Javascript variable, and iterate the resulting object with jQuery.
  23. Because there are many elements, and I am never sure what will be contained in the PHP variable $non_matches. JSG: Please see my above edit. It may prove useful in your further response.
  24. Hi, Ingolme! I can see how use of the term form element can lead to confusion. On the one hand, it refers to the form tag <form>; on the other hand, it refers to any HTML element related directly to the creation of a form -- both non-control and control elements alike. Since the form attribute of the fieldset element is not recognized by any recent browser (see W3Schools), I will assume that it is a non-control form element only useful for decoration and the organization of form-control elements. To play it safe I will remove all of my non-essential <form> tags. Originally, all of my control-elements pointed to the same <form> tag, but each was grouped with other control elements in different <form> tags that did not contain a type='submit' control element.