...

View Full Version : HTML Header Script



Dormilich
01-19-2010, 11:34 AM
This script is intended to ease the output of HTML headers (server and client side). Just define the type, language and encoding of the document and the script will take care of the (X)HTML output. There are additional features built in (deny to serve, custom XHTML), that may come in handy.


<?php
/*
* class.headers.php
*
* Copyright 2009 Alexander Stranzky <Dormilich@netscape.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

###########################################################
# printing DOCTYPE, <HTML>, <HEAD>, <META "content-type"> #
###########################################################

/**
* Based on the Function by Dave Shea.
*
* due to IE's lack of support for "application/xhtml+xml" (XHTML 1.1
* recommended MIME type) a browser switch (XHTML/HTML) is made. All
* browsers accepting "application/xhtml+xml" will be served with the
* default output (which is currently XHTML 1.0) for all others the
* output will be buffered and corrected towards HTML 4.01.
* XHTML Coders: empty elements that are not empty or don't have an
* optional closing tag in HTML are thus likely to inflict problems.
*
* How to set the options
* ======================
* there are 5 options available:
* - Document MIME type (HTML 4.01, HTML 5, XHTML 1.0, XHTML 1.1, XHTML)
* - Document language
* - Document encoding (character set)
* - Script language MIME type
* - Stylesheet MIME type (currently disabled)
* - Denial to Serve (if the MIME type is not supported)
*
* of which the first 3 can be set using the class' constructor, but all
* of them can be set later as they are public properties. Should you choose
* to take the 'XHTML' MIME type, you need to set the DTD string beforehand.
* This will be required, when you need to use 'mixed' XHTML types, such as
* XHTML+SVG, XHTML+MathML, XHTML+RDFa, etc.
* You can choose to deny serving XHTML to User Agents (UA) that do not
* support the set MIME type by setting $errorCode to a HTTP Client Error
* Code (4xx). A denied document does not contain any data, so UA don't
* display any message. However you can read the HTTP Response Headers. You
* can forcibly deny a document by calling the deny() method.
* Note that XHTML 1.1 can only be served using "application/xhtml+xml".
*/
class Headers
{
/**
* @const (string) DTD_XHTML_10 XHTML 1.0 Strict DTD
* @const (string) DTD_XHTML_11 XHTML 1.1 DTD
* @const (string) DTD_HTML_401 HTML 4.01 Strict DTD
* @const (string) DTD_HTML_5 HTML 5 DTD
* @const (string) XMLNS_XHTML XHTML namespace
* @const (string) META_TYPE_CSS meta element defining the default
* style MIME type
* @const (string) META_TYPE_JS meta element defining the default
* script MIME type
* @const (string) MIME_TYPE_CSS MIME type for CSS files
* @const (string) MIME_TYPE_JS MIME type for JavaScript files
* @const (string) MIME_TYPE_XML MIME type for XML text files
* @const (string) MIME_TYPE_HTML MIME type for HTML files
* @const (string) MIME_TYPE_XHTML MIME type for XHTML files
* @var (array) HTTP_ERROR_MSG HTTP Error Codes 4xx series (RFC 2616)
* @var (string) $mime default page MIME type
* @var (string) $mime_js JavaScript MIME type (changeable)
* @var (string) $mime_css CSS MIME type (changeable)
* @var (string) $type default page type ((X)HTML),
* may be edited by the user
* @var (string) $encoding page encoding/charset,
* may be edited by the user
* @var (string) $language default page language,
* may be edited by the user
* @var (string) $dtd used for a custom DTD
* @var (mixed) $errorCode HTTP Error Code to send or false
* for XHTML -> HTML conversion
*/
const DTD_XHTML_10 = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
const DTD_XHTML_11 = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
const DTD_HTML_401 = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">';
const DTD_HTML_5 = '<!DOCTYPE html>';

const XMLNS_XHTML = 'xmlns="http://www.w3.org/1999/xhtml"';

const META_TYPE_CSS = '<meta http-equiv="content-style-type" content="text/css"/>';
const META_TYPE_JS = '<meta http-equiv="content-script-type" content="%s"/>';
const MIME_TYPE_JS = 'text/javascript';
const MIME_TYPE_CSS = 'text/css';
const MIME_TYPE_XML = 'text/xml';
const MIME_TYPE_HTML = 'text/html';
const MIME_TYPE_XHTML = 'application/xhtml+xml';

protected static $HTTP_ERROR_MSG = array(
400 => "Bad Request",
401 => "Unauthorized",
402 => "Payment Required",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
406 => "Not Acceptable",
407 => "Proxy Authentication Required",
408 => "Request Timeout",
409 => "Conflict",
410 => "Gone",
411 => "Length Required",
412 => "Precondition Failed",
413 => "Request Entity Too Large",
414 => "Request-URI Too Long",
415 => "Unsupported Media Type",
416 => "Requested Range Not Satisfiable",
417 => "Expectation Failed"
);

public $mime = 'text/html';
public $mime_js = 'text/javascript';
/*
'text/ecmascript'
'application/javascript'
'application/ecmascript'
*/
public $mime_css = 'text/css';
public $type = 'XHTML 1.0';
public $encoding = 'UTF-8';
public $language = 'de';
public $dtd = '';
public $errorCode = false;

/**
* determine the supported MIME type. set defaults.
*
* @param (string) $encoding encoding/charset of the document [UTF-8]
* @param (string) $lang used language [de]
* @param (string) $type used DTD/HTML version [XHTML 1.1]
* @return (void)
*/
public function __construct(
$encoding = 'UTF-8',
$lang = 'de',
$type = 'XHTML 1.0'
)
{
$this->type = $type;
$this->encoding = $encoding;
$this->language = $lang;
# set defaults
$this->mime_css = self::MIME_TYPE_CSS;
$this->mime_js = self::MIME_TYPE_JS;
# determine possible MIME type for XHTML
$this->changeMIME();
$this->specialUA();
}

/**
* setter method for the encoding/charset property.
*
* @return (Headers) instance for chaining
*/
public function setEncoding(
$charset = 'UTF-8'
)
{
$this->encoding = $charset;
return $this;
}

/**
* setter method for language property.
*
* @return (Headers) instance for chaining
*/
public function setLanguage(
$lang = 'de'
)
{
$this->language = $lang;
return $this;
}

/**
* setter method for Doctype identifyer.
*
* @return (Headers) instance for chaining
*/
public function setDocType(
$type = 'XHTML 1.0'
)
{
$this->type = strtoupper($type);
return $this;
}

/**
* Send a HTTP Status Code of the 4xx series (Client Errors) to the client.
*
* @param (int) $code HTTP Error Code Number
* @throws (CodeException) not a Client Error Code
*/
public function deny(
$code = 406
)
{
if (!isset(self::$HTTP_ERROR_MSG[$code]))
{
$emsg = "Only Client Error HTTP Status Codes supported.";
throw new Exception($emsg);
}
header("HTTP/1.1 $code " . self::$HTTP_ERROR_MSG[$code]);
header("Status: $code " . self::$HTTP_ERROR_MSG[$code]);
header("Connection: Close");
exit;
}

/**
* send PHP headers and print the (X)HTML headers. if MIME type is set to
* HTML, start the output correction (XHTML -> HTML) via output buffer.
*
* @return (string) HTML headers
*/
public function __toString()
{
# reset MIME type for HTML documents
if ('HTML 4.01' == $this->type)
{
$this->mime = self::MIME_TYPE_HTML;
# otherwise leave it at XHTML
}
# convenience variable
$_isXHTML = is_int(strpos($this->type, 'XHTML'));

# don't serve XHTML 1.1 to UAs that don't know "application/xhtml+xml"
if ('XHTML 1.1' == $this->type and self::MIME_TYPE_XHTML != $this->mime)
{
$this->deny(406);
}
# forcibly don't serve XHTML to UAs that don't know "application/xhtml+xml"
if ($_isXHTML and self::MIME_TYPE_XHTML != $this->mime and is_int($this->errorCode))
{
$this->deny($this->errorCode);
}
# remove empty xml tag notation ("/>" -> ">")
if ($_isXHTML and self::MIME_TYPE_HTML == $this->mime)
{
ob_start(array($this, "fix_code"));
}
# send headers
header("Content-Type: " . $this->mime . ";charset=" . $this->encoding);
header("Vary: Accept");

# choose page type from MIME type
if (self::MIME_TYPE_HTML == $this->mime)
{
$type = 'HTML 4.01';
}
else
{
$type = $this->type;
}
return $this->getHeader($type);
}

/**
* read the q-value (MIME type weighting) from HTTP_ACCEPT and set
* the according MIME type. if support for XHTML is detected, change
* the MIME type from HTML (default) to XHTML.
*
* @return (void)
*/
protected function changeMIME()
{
$preg_xhtml = "@application/xhtml\+xml;q=0(\.[1-9]+)@i";
$preg_html = "@text/html;q=0(\.[1-9]+)@i";

# close connection for non-browsers (no Accept header)
if (!isset($_SERVER["HTTP_ACCEPT"]))
{
$this->deny(406);
}

// $this->mime = self::MIME_TYPE_HTML;

// change
# match without q-value
if (stristr($_SERVER["HTTP_ACCEPT"], self::MIME_TYPE_XHTML))
{
# match with q-value
if (preg_match($preg_xhtml, $_SERVER["HTTP_ACCEPT"], $matches))
{
# compare html/xhtml from q-value
$xhtml_q = $matches[1];
if (preg_match($preg_html, $_SERVER["HTTP_ACCEPT"], $matches))
{
$html_q = $matches[1];
if ($xhtml_q >= $html_q)
{
$this->mime = self::MIME_TYPE_XHTML;
}
}
}
else
{
$this->mime = self::MIME_TYPE_XHTML;
}
}
}

/**
* correct the MIME type for some special User Agents that are not
* correctly recognized by self::changeMIME() or which contain bugs
* that would lead to errors.
*
* @return (bool) HTTP_USER_AGENT available
*/
protected function specialUA()
{
if (!isset($_SERVER["HTTP_USER_AGENT"]))
{
return false;
}
# special check for the W3C_Validator
if (stristr($_SERVER["HTTP_USER_AGENT"], "W3C_Validator"))
{
$this->mime = self::MIME_TYPE_XHTML;
}
# special check for Shiira
if (stristr($_SERVER["HTTP_USER_AGENT"], "Shiira"))
{
$this->mime = self::MIME_TYPE_HTML;
}
return true;
}

/**
* build the headers (from XML Prolog to <meta>s) according to the
* set MIME type.
*
* @param (string) $type MIME type
* @return (string) headers formatted for printing
*/
public function getHeader(
$type = 'XHTML'
)
{
# XML Prolog
$xml = '<?xml version="1.0" encoding="' . $this->encoding . "\" ?>\n";
$meta = '
<head>
<meta http-equiv="content-type" content="' . $this->mime . ';charset=' . $this->encoding . '"/>';

switch ($type)
{
case 'XHTML 1.1':
# DTD
$dtd = self::DTD_XHTML_11 . "\n";
# <html>
$html = '<html '
. self::XMLNS_XHTML
. ' xml:lang="' . $this->language . '">';
break;

case 'XHTML 1.0':
# DTD
$dtd = self::DTD_XHTML_10 . "\n";
# <html>
$html = '<html '
. self::XMLNS_XHTML
. ' xml:lang="' . $this->language . '"'
. ' lang="' . $this->language . '">';
break;

// XHTML special types like XHTML+SVG, XHTML+MathML, etc.
case 'XHTML':
# DTD
$dtd = $this->dtd;
# <html>
$html = '<html '
. self::XMLNS_XHTML
. ' xml:lang="' . $this->language . '">';
break;

case 'XHTML 5':
# DTD
$dtd = self::DTD_HTML_5 . "\n";;
# <html>
$html = '<html '
. self::XMLNS_XHTML
. ' xml:lang="' . $this->language . '">';
break;

case 'HTML 5':
# no XML prolog
$xml = '';
# DTD
$dtd = self::DTD_HTML_5 . "\n";;
# <html>
$html = '<html lang="' . $this->language . '">';
break;

case 'HTML 4.01':
default:
# no XML prolog
$xml = '';
# DTD
$dtd = self::DTD_HTML_401 . "\n";
# <html>
$html = '<html lang="' . $this->language . '">';
# <meta>
break;
}

$header = $xml . $dtd . $html . $meta
. "\n\t\t" . self::META_TYPE_CSS
. "\n\t\t" . sprintf(self::META_TYPE_JS, $this->mime_js);
return $header;
}

/**
* convert XHTML to HTML (basicly treating the empty elements)
*
* @param (string) $buffer content from the output buffer
* @return (string) HTML code to send to the browser
*/
public function fix_code($buffer)
{
return (str_replace("/>", ">", $buffer));
}
}
?>
example usage:

<?php
echo new Headers("ISO-8859-1", "en");
?>

// output IE
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
<meta http-equiv="content-style-type" content="text/css">
<meta http-equiv="content-script-type" content="text/javascript">

// output other browsers
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="application/xhtml+xml;charset=ISO-8859-1"/>
<meta http-equiv="content-style-type" content="text/css"/>
<meta http-equiv="content-script-type" content="text/javascript"/>

<?php
$h = new Headers;
$h->setDocType("XHTML 1.1")
->mime_js = "application/ecmascript";
echo $h;
?>
// output IE

// output other browsers
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>
<meta http-equiv="content-type" content="application/xhtml+xml;charset=UTF-8"/>
<meta http-equiv="content-style-type" content="text/css"/>
<meta http-equiv="content-script-type" content="application/ecmascript"/>

Note on the attached file: this script uses a custom Exception for better Error Handling, thus change line #218 apropriately.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum