2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997 - 2003 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.0 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Adam Daniel <adaniel1@eesus.jnj.com> |
17 // | Klaus Guenther <klaus@capitalfocus.org> |
18 // +----------------------------------------------------------------------+
21 require_once 'PEAR.php';
22 require_once 'Common.php';
25 * Base class for XHTML pages
27 * This class handles the details for creating a properly constructed XHTML page.
28 * Page caching, stylesheets, client side script, and Meta tags can be
29 * managed using this class.
31 * The body may be a string, object, or array of objects or strings. Objects with
32 * toHtml() and toString() methods are supported.
41 * // the default doctype is XHTML 1.0 Transitional
42 * // All doctypes and defaults are set in HTML/Page/Doctypes.php
43 * $p = new HTML_Page();
46 * $p->addBodyContent("<p>some text</p>");
52 * Complex XHTML example:
53 * ----------------------
55 * // The initializing code can also be in in the form of an HTML
56 * // attr="value" string.
57 * // Possible attributes are: charset, lineend, tab, doctype, language and cache
59 * $p = new HTML_Page(array (
61 * // Sets the charset encoding
62 * 'charset' => 'utf-8',
64 * // Sets the line end character
65 * // unix (\n) is default
66 * 'lineend' => 'unix',
68 * // Sets the tab string for autoindent
69 * // tab (\t) is default
72 * // This is where you define the doctype
73 * 'doctype' => "XHTML 1.0 Strict",
75 * // Global page language setting
78 * // If cache is set to true, the browser may
79 * // cache the output. Else
85 * // Set the page title
86 * $p->setTitle("My page");
88 * // Add optional meta data
89 * $p->addMetaData("author", "My Name");
91 * // Put something into the body
92 * $p->addBodyContent = "<p>some text</p>";
94 * // If at some point you want to clear the page content
95 * // and output an error message, you can easily do that
96 * // See the source for {@link toHtml} and {@link _getDoctype}
99 * $p->setTitle("Error!");
100 * $p->setBodyContent("<p>oops, we have an error: $error</p>");
103 * } // end error handling
105 * // print to browser
109 * Simple XHTML declaration example:
111 * $p = new HTML_Page();
112 * // An XHTML compliant page (with title) is automatically generated
114 * // This overrides the XHTML 1.0 Transitional default
115 * $p->setDoctype('xhtml');
117 * // Put some content in here
118 * $p->addBodyContent("<p>some text</p>");
120 * // print to browser
131 * $p = new HTML_Page('doctype="HTML 4.01 Strict"');
132 * $p->addBodyContent = "<p>some text</p>";
136 * nuke doctype declaration:
137 * -------------------------
139 * $p = new HTML_Page('doctype="none"');
140 * $p->addBodyContent = "<p>some text</p>";
144 * @author Adam Daniel <adaniel1@eesus.jnj.com>
145 * @author Klaus Guenther <klaus@capitalfocus.org>
147 * @since PHP 4.0.3pl1
149 class HTML_Page extends HTML_Common {
152 * Contains the content of the <body> tag.
157 var $_body = array();
160 * Controls caching of the page
168 * Contains the character encoding string
173 var $_charset = 'utf-8';
176 * Contains the !DOCTYPE definition
181 var $_doctype = array('type'=>'xhtml','version'=>'1.0','variant'=>'transitional');
184 * Contains the page language setting
189 var $_language = 'en';
197 var $_metaTags = array( 'standard' => array ( 'Generator' => 'PEAR HTML_Page' ) );
200 * Array of linked scripts
205 var $_scripts = array();
208 * Array of linked scripts
213 var $_simple = false;
216 * Array of included style declarations
221 var $_style = array();
224 * Array of linked style sheets
229 var $_styleSheets = array();
241 * Possible attributes are:
243 * - "lineend" => "unix|win|mac" (Sets line ending style; defaults to unix.)
244 * - "tab" => string (Sets line ending style; defaults to \t.)
245 * - "cache" => "false|true"
246 * - "charset" => charset string (Sets charset encoding; defaults to utf-8)
248 * - "doctype" => mixed (Sets XHTML doctype; defaults to XHTML 1.0 Transitional.)
249 * - "language" => two letter language designation. (Defines global document language; defaults to "en".)
251 * @param mixed $attributes Associative array of table tag attributes
252 * or HTML attributes name="value" pairs
255 function HTML_Page($attributes = "")
257 $commonVersion = 1.7;
258 if (HTML_Common::apiVersion() < $commonVersion) {
259 return PEAR::raiseError("HTML_Page version " . $this->apiVersion() . " requires " .
260 "HTML_Common version $commonVersion or greater. You can get the (still) unofficial ".
261 "update here: http://www.geist.uni-freiburg.de/pear/HTML/Common.txt", 0, PEAR_ERROR_TRIGGER);
265 $attributes = $this->_parseAttributes($attributes);
268 if (isset($attributes['lineend'])) {
269 $this->setLineEnd($attributes['lineend']);
272 if (isset($attributes['charset'])) {
273 $this->setCharset($attributes['charset']);
276 if (isset($attributes['doctype'])){
277 if ($attributes['doctype'] == 'none') {
278 $this->_simple = true;
279 } elseif ($attributes['doctype']) {
280 $this->setDoctype($attributes['doctype']);
284 if (isset($attributes['language'])) {
285 $this->setLang($attributes['language']);
288 if (isset($attributes['cache'])) {
289 $this->setCache($attributes['cache']);
295 * Generates the HTML string for the <body< tag
300 function _generateBody()
304 $lnEnd = $this->_getLineEnd();
305 $tab = $this->_getTab();
307 // If body attributes exist, add them to the body tag.
308 // Depreciated because of CSS
309 $strAttr = $this->_getAttrString($this->_attributes);
312 $strHtml = "<body $strAttr>" . $lnEnd;
314 $strHtml = '<body>' . $lnEnd;
317 // Allow for mixed content in the body array
318 // Iterate through the array and process each element
319 foreach ($this->_body as $element) {
320 if (is_object($element)) {
321 if (is_subclass_of($element, "html_common")) {
322 $element->setTab($tab);
323 $element->setTabOffset(1);
324 $element->setLineEnd($lnEnd);
326 if (method_exists($element, "toHtml")) {
327 $strHtml .= $element->toHtml() . $lnEnd;
328 } elseif (method_exists($element, "toString")) {
329 $strHtml .= $element->toString() . $lnEnd;
331 } elseif (is_array($element)) {
332 foreach ($element as $level2) {
333 if (is_subclass_of($level2, "html_common")) {
334 $level2->setTabOffset(1);
335 $level2->setTab($tab);
336 $level2->setLineEnd($lnEnd);
338 if (is_object($level2)) {
339 if (method_exists($level2, "toHtml")) {
340 $strHtml .= $level2->toHtml() . $lnEnd;
341 } elseif (method_exists($level2, "toString")) {
342 $strHtml .= $level2->toString() . $lnEnd;
345 $strHtml .= $tab . $level2 . $lnEnd;
349 $strHtml .= $tab . $element . $lnEnd;
354 $strHtml .= '</body>' . $lnEnd;
358 } // end func _generateHead
361 * Outputs a page containing the error message and then dies
366 function _error(&$error){
368 $this->setTitle('HTML_Page doctype Error');
369 $this->setBody('<p>' . $error->getMessage() . '</p>');
377 * Generates the HTML string for the <head< tag
382 function _generateHead()
386 $lnEnd = $this->_getLineEnd();
387 $tab = $this->_getTab();
389 $strHtml = '<head>' . $lnEnd;
390 $strHtml .= $tab . '<title>' . $this->getTitle() . '</title>' . $lnEnd;
392 // Generate META tags
393 foreach ($this->_metaTags as $type => $tag) {
394 foreach ($tag as $name => $content) {
395 if ($type == 'http-equiv') {
396 $strHtml .= $tab . "<meta http-equiv=\"$name\" content=\"$content\" />" . $lnEnd;
397 } elseif ($type == 'standard') {
398 $strHtml .= $tab . "<meta name=\"$name\" content=\"$content\" />" . $lnEnd;
403 // Generate stylesheet links
404 for($intCounter=0; $intCounter<count($this->_styleSheets); $intCounter++) {
405 $strStyleSheet = $this->_styleSheets[$intCounter];
406 $strHtml .= $tab . "<link rel=\"stylesheet\" href=\"$strStyleSheet\" type=\"text/css\" />" . $lnEnd;
409 // Generate stylesheet declarations
410 foreach ($this->_style as $type => $content) {
411 $strHtml .= $tab . '<style type="' . $type . '">' . $lnEnd;
412 $strHtml .= $tab . $tab . '<!--' . $lnEnd;
413 if (is_object($content)) {
414 if (is_subclass_of($content, "html_common")) {
415 $content->setTab($tab);
416 $content->setTabOffset(3);
417 $content->setLineEnd($lnEnd);
419 if (method_exists($content, "toString")) {
420 $strHtml .= $content->toString() . $lnEnd;
423 $strHtml .= $content . $lnEnd;
425 $strHtml .= $tab . $spacer . "-->" . $lnEnd;
426 $strHtml .= $tab . "</style>" . $lnEnd;
429 // Generate script file links
430 for($intCounter=0; $intCounter<count($this->_scripts); $intCounter++) {
431 $strType = $this->_scripts[$intCounter]["type"];
432 $strSrc = $this->_scripts[$intCounter]["src"];
433 $strHtml .= $tab . "<script type=\"$strType\" src=\"$strSrc\"></script>" . $lnEnd;
437 $strHtml .= '</head>' . $lnEnd;
441 } // end func _generateHead
444 * Returns the doctype declaration
449 function _getDoctype()
451 include('Page/Doctypes.php');
453 $type = $this->_doctype['type'];
454 $version = $this->_doctype['version'];
455 $variant = $this->_doctype['variant'];
459 if ($variant != '') {
460 if (isset($doctype[$type][$version][$variant][0])) {
461 foreach ( $doctype[$type][$version][$variant] as $string) {
462 $strDoctype .= $string.$this->_getLineEnd();
465 } elseif ($version != '') {
466 if (isset($doctype[$type][$version][0])) {
467 foreach ( $doctype[$type][$version] as $string) {
468 $strDoctype .= $string.$this->_getLineEnd();
471 if (isset($default[$type][$version][0])) {
472 $this->_doctype = $this->_parseDoctypeString($default[$type][$version][0]);
473 $strDoctype = $this->_getDoctype();
476 } elseif ($type != '') {
477 if (isset($default[$type][0])){
478 $this->_doctype = $this->_parseDoctypeString($default[$type][0]);
479 $strDoctype = $this->_getDoctype();
482 $this->_doctype = $this->_parseDoctypeString($default['default'][0]);
483 $strDoctype = $this->_getDoctype();
489 return PEAR::raiseError('Error: "'.$this->getDoctypeString().'" is an unsupported or illegal document type.',
490 0,PEAR_ERROR_RETURN);
493 } // end func _getDoctype
496 * Parses a doctype declaration like "XHTML 1.0 Strict" to an array
498 * @param string $string The string to be parsed
502 function _parseDoctypeString($string)
504 $split = explode(' ',strtolower($string));
505 $elements = count($split);
507 $array = array('type'=>$split[0],'version'=>$split[1],'variant'=>$split[2]);
510 } // end func _parseDoctypeString
513 * Sets the content of the <body> tag. If content already exists,
514 * the new content is appended.
515 * If you wish to overwrite whatever is in the body, use {@link setBody};
516 * {@link unsetBody} completely empties the body without inserting new content.
517 * It is possible to add objects, strings or an array of strings and/or objects
519 * @param mixed $content New <body> tag content.
522 function addBodyContent($content)
524 $this->_body[] =& $content;
525 } // end addBodyContent
528 * Depreciated. Sets or alters a meta tag. Use {@link setMetaData} instead.
529 * This function only allows for standard META tags.
531 * @param string $name Value of name or http-equiv tag
532 * @param string $content Value of the content tag
535 function addMetaData($name, $content)
537 $this->setMetaData($name, $content);
538 } // end func addMetaData
541 * Adds a linked script to the page
543 * @param string $url URL to the linked style sheet
544 * @param string $type Type of script. Defaults to 'text/javascript'
547 function addScript($url, $type="text/javascript")
549 $this->_scripts[] = array("type"=>$type, "src"=>$url);
550 } // end func addScript
553 * Adds a linked style sheet to the page
555 * @param string $url URL to the linked style sheet
558 function addStyleSheet($url)
560 $this->_styleSheets[] = $url;
561 } // end func addStyleSheet
564 * Adds a linked style sheet to the page
566 * @param string $type Type of stylesheet (e.g., text/css)
567 * @param string $content Style declarations
570 function addStyleDeclaration($type, $content)
572 $this->_style[$type] =& $content;
573 } // end func addStyleDeclaration
576 * Returns the current API version
581 function apiVersion()
584 } // end func apiVersion
587 * Outputs the HTML content to the screen.
593 if(! $this->_cache) {
594 header("Expires: Tue, 1 Jan 1980 12:00:00 GMT");
595 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
596 header("Cache-Control: no-cache");
597 header("Pragma: no-cache");
600 // set character encoding
601 header("Content-Type: text/html; charset=" . $this->_charset);
603 $strHtml = $this->toHTML();
605 } // end func display
608 * Defines if the document should be cached by the browser. Defaults to false.
610 * @param string $cache Options are currently 'true' or 'false'. Defaults to 'false'.
613 function getCharset()
615 return $this->_charset;
619 * Returns the document type string
624 function getDoctypeString()
626 $strDoctype = strtoupper($this->_doctype['type']);
627 $strDoctype .= ' '.ucfirst(strtolower($this->_doctype['version']));
628 if ($this->_doctype['variant']) {
629 $strDoctype .= ' ' . ucfirst(strtolower($this->_doctype['variant']));
631 return trim($strDoctype);
632 } // end func getDoctypeString
635 * Returns the document language.
642 return $this->_language;
643 } // end func getLang
646 * Return the title of the page.
654 if ($this->_simple) {
657 return 'New '. $this->getDoctypeString() . ' Compliant Page';
660 return $this->_title;
662 } // end func getTitle
665 * Sets or alters the XHTML !DOCTYPE declaration. Can be set to "strict",
666 * "transitional" or "frameset". Defaults to "transitional". This must come
667 * _after_ declaring the character encoding with {@link setCharset} or directly
668 * when the class is initiated {@link HTML_Page}.
670 * @param mixed $type String containing a document type. Defaults to "XHTML 1.0 Transitional"
673 function setDoctype($type = "XHTML 1.0 Transitional")
675 $this->_doctype = $this->_parseDoctypeString($type);
676 } // end func setDoctype
679 * Sets the global document language declaration. Default is English.
682 * @param string $lang Two-letter language designation.
684 function setLang($lang = "en")
686 $this->_language = strtolower($lang);
690 * Sets the content of the <body> tag. If content exists, it is overwritten.
691 * If you wish to use a "safe" version, use {@link addBodyContent}
693 * @param mixed &$content New <body> tag content.
696 function setBody(&$content)
699 $this->_body[] =& $content;
703 * Defines if the document should be cached by the browser. Defaults to false.
705 * @param string $cache Options are currently 'true' or 'false'. Defaults to 'false'.
708 function setCache($cache = 'false')
710 if ($cache == 'true'){
711 $this->_cache = true;
713 $this->_cache = false;
718 * Defines if the document should be cached by the browser. Defaults to false.
720 * @param string $cache Options are currently 'true' or 'false'. Defaults to 'false'.
723 function setCharset($type = 'utf-8')
725 $this->_charset = $type;
729 * Sets or alters a meta tag.
731 * @param string $name Value of name or http-equiv tag
732 * @param string $content Value of the content tag
733 * @param bool $http_equiv META type "http-equiv" defaults to NULL
736 function setMetaData($name, $content, $http_equiv = false)
738 if ($http_equiv == true) {
739 $this->_meta['http-equiv'][$name] = $content;
741 $this->_meta['standard'][$name] = $content;
743 } // end func setMetaData
746 * Easily sets or alters a refresh meta tag.
747 * If no $url is passed, "self" is presupposed, and the appropriate URL
748 * will be automatically generated.
750 * @param string $time Time till refresh (in seconds)
751 * @param string $url Absolute URL or "self"
752 * @param bool $https If $url = self, this allows for the https protocol
755 function setMetaRefresh($time, $url = 'self', $https = false)
757 if ($url == 'self') {
759 $protocol = 'https://';
761 $protocol = 'http://';
763 $url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
765 $this->setMetaData("Refresh", "$time; url=$url", true);
766 } // end func setMetaRefresh
769 * Sets the title of the page
771 * @param string $title
774 function setTitle($title)
776 $this->_title = $title;
777 } // end func setTitle
780 * Generates and returns the complete page as a string.
789 $lnEnd = $this->_getLineEnd();
790 $strDoctype = $this->_getDoctype();
791 if (!PEAR::isError($strDoctype)){
793 if ($this->_simple) {
794 $strHtml = '<html>' . $lnEnd;
795 } elseif ($this->_doctype['type'] == 'xhtml') {
796 $strHtml = '<?xml version="1.0" encoding="' . $this->_charset . '"?>' . $lnEnd;
797 $strHtml .= $strDoctype . $lnEnd;
798 $strHtml .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$this->_language.'">';
800 $strHtml = $strDoctype . $lnEnd;
801 $strHtml .= '<html>' . $lnEnd;
806 $this->_error($strDoctype);
809 $strHtml .= $this->_generateHead();
810 $strHtml .= $this->_generateBody();
811 $strHtml .= '</html>';
816 * Unsets the content of the <body> tag.