Cnz_Html
[ class tree: Cnz_Html ] [ index: Cnz_Html ] [ all elements ]

Source for file Html.php

Documentation is available at Html.php

  1. <?php
  2. /**
  3.  * CNZ Framework
  4.  *
  5.  * A Framework for Creating and Using Complex Web Elements
  6.  *
  7.  * The purpose of this framework is to provide a library of high-level objects
  8.  * to facilitate common HTML coding tasks, such as menus, tables, and forms.
  9.  * The intent is to reduce repetitive HTML coding as much as possible, replacing
  10.  * it with a combination of configuration files and style sheets with
  11.  * standardized naming conventions.
  12.  *
  13.  * This framework is built on and requires the
  14.  * {@link http://framework.zend.com/ Zend Framework}.
  15.  *
  16.  * @category Cnz
  17.  * @package  Cnz_Html
  18.  *
  19.  * @author    Lyle Frost <lfrost@cnz.com>
  20.  * @copyright Copyright (c) 2006-2007 Citadel Network <{@link http://www.citadelnetwork.com/}>
  21.  * @filesource
  22.  * @license   http://www.citadelnetwork.com/license/cnzframework New BSD License
  23.  * @version   $Id: Html.php 27 2007-07-19 18:47:54Z lfrost $
  24.  */
  25.  
  26. /**
  27.  * Required classes.
  28.  *
  29.  * @ignore
  30.  */
  31. Zend_Loader::loadClass('Zend_Config');
  32. Zend_Loader::loadClass('Zend_Config_Ini');
  33. Zend_Loader::loadClass('Zend_Log');
  34. Zend_Loader::loadClass('Zend_Log_Filter_Priority');
  35. Zend_Loader::loadClass('Zend_Log_Writer_Stream');
  36.  
  37. /**
  38.  * HTML class
  39.  *
  40.  * This utility class provides general HTML support methods.
  41.  *
  42.  * To use this class, load the class <kbd>Cnz_Html</kbd> and then call the
  43.  * static method <kbd>init()</kbd> prior to any output on the web page.  The
  44.  * class is controlled by a configuration file.
  45.  *
  46.  * Example INI (defaults shown as comments):
  47.  *
  48.  * <pre><samp>
  49.  * [Html]
  50.  * domain          = www.example.com
  51.  * sslDomain       = www.example.com
  52.  * ;charSets       = utf-8
  53.  * ;languages      = en-us
  54.  * ;transitional   = no
  55.  * ;indent         = \t
  56.  * wcagLevel       = AAA
  57.  * ;brickDir       = /slib/image/brick/
  58.  * ;buttonDir      = /slib/image/button/
  59.  * ;logDir         = log
  60.  * ;tmpDir         = tmp
  61.  * ;uploadDir      = upload
  62.  * ;logFile        = html.log
  63.  * ;logLevel       = info
  64.  * phpLogFile      = php.log
  65.  * phpLogLevel     = E_STRICT
  66.  * </samp></pre>
  67.  *
  68.  * <var>brickDir</var> is for link bricks such as the W3C validation bricks.
  69.  * <var>buttonDir</var> is for control buttons such as table next/prev.
  70.  *
  71.  * <var>indent</var> defines the string used for a single level of HTML
  72.  * indentation.
  73.  *
  74.  * <var>tmpDir</var> and <var>logDir</var> are relative to the application root
  75.  * directory, which is defined to be the parent of the web document root
  76.  * directory.
  77.  *
  78.  * <var>logLevel</var> can be any of the log levels defined by Zend_Log (debug,
  79.  * info, notice, warn, err, crit, alert, or severe).
  80.  *
  81.  * Example PHP:
  82.  *
  83.  * <code>
  84.  * Zend_Loader::loadClass('Cnz_Html');
  85.  * Cnz_Html::init();
  86.  * </code>
  87.  *
  88.  * The <kbd>init()</kbd> method will detect the capabilities of the client web
  89.  * browser and send the appropriate HTTP headers.  XHTML 1.1 will be chosen as
  90.  * the content type if the browser prefers XHTML, else the content type will be
  91.  * set to HTML 4.01 Strict.  If transitional is true, these will instead be
  92.  * XHTML 1.0 Transitional and HTML 4.01 Transitional, respectively.
  93.  *
  94.  * <kbd>init()</kbd> also compares the list of languages in the configuration
  95.  * file to those in the <kbd>Accept-Language</kbd> header to find the best
  96.  * match.  If there is no match, the language defaults to the first in the
  97.  * configuration list.  The match can be retrieved using
  98.  * <kbd>getLanguage()</kbd>.
  99.  *
  100.  * <kbd>init()</kbd> processes the <kbd>Accept-Charset</kbd> header in the same
  101.  * way.  Use <kbd>getCharSet()</kbd> to retrieve the selected character set.
  102.  *
  103.  * Based on the detections above, the appropriate HTTP response headers are
  104.  * generated, and all prolog information up to and including the <kbd>html</kbd>
  105.  * start tag is output.
  106.  *
  107.  * Given that the most common scenario for a database-driven site is to have a
  108.  * single database, <kbd>init()</kbd> has an option of connecting to that
  109.  * database.  This connection is defined by passing a second argument to
  110.  * <kbd>init()</kbd> which is the name of the database configuration file.  This
  111.  * is allowed to be in a separate file because it contains security information.
  112.  * The connection is a <kbd>Zend_Db_Adapter</kbd>.
  113.  *
  114.  * A third boolean parameter specifies whether the connection will be made
  115.  * immediately, or postponed until it is accessed.
  116.  *
  117.  * <pre><samp>
  118.  * [Database]
  119.  * type        = pgsql
  120.  * host        = localhost
  121.  * port        = database_port
  122.  * dbname      = database_name
  123.  * username    = database_user
  124.  * password    = database_password
  125.  * </samp></pre>
  126.  *
  127.  * The valid database type values are:  <kbd>dblib</kbd>, <kbd>firebird</kbd>,
  128.  * <kbd>informix</kbd>, <kbd>mysql</kbd>, <kbd>oci</kbd>, <kbd>odbc</kbd>,
  129.  * <kbd>pgsql</kbd>, <kbd>sqlite</kbd>.  See <kbd>PDO_*</kbd> at
  130.  * {@link http://www.php.net/manual/en/ref.pdo.php}.  Additionally, the non-PDO
  131.  * database types <kbd>db2</kbd> and <kbd>oracle</kbd> may be used.
  132.  *
  133.  * Leave the host undefined for socket connections.
  134.  *
  135.  * Pages using this class must be written with XHTML syntax.  If the end-tag
  136.  * shorthand sequence "<kbd>/></kbd>" occurs anywhere else in the text, it must
  137.  * be replaced with "<kbd>/&gt;</kbd>" or else the "<kbd>/</kbd>" (and any
  138.  * preceding whitespace) will be stripped when the page is served as HTML.
  139.  *
  140.  * When using JavaScript, the value of the <kbd>type</kbd> attribute of the
  141.  * script tag should be set as follows.
  142.  *
  143.  * <pre><samp>
  144.  * type = "&lt;?php echo Cnz_Html::getJavascriptType(); ?>"
  145.  * </samp></pre>
  146.  *
  147.  * There are also getter methods for several other settings.
  148.  *
  149.  * The following directory structure is recommended.  The recommended * BASE is
  150.  * /srv/www/host/.
  151.  *
  152.  * <pre>
  153.  * $BASE --- app  Application code
  154.  *        |
  155.  *        |- cfg  Configurations
  156.  *        |  |
  157.  *        |  |- form    Form configurations
  158.  *        |  |- table   Table configurations
  159.  *        |
  160.  *        |- dat  Data files
  161.  *        |  |
  162.  *        |  |- table  Table data
  163.  *        |
  164.  *        |- doc  Documentation
  165.  *        |
  166.  *        |- log  Log files
  167.  *        |
  168.  *        |- tmp  Temporary files
  169.  *        |
  170.  *        |- upload  Temporary upload directory
  171.  *        |
  172.  *        |- www  Web document root
  173.  *           |
  174.  *           |- image   Images (local to current directory)
  175.  *           |- lib     Site library
  176.  *           |  |- image   Images
  177.  *           |  |- script  Client-side Scripts
  178.  *           |  |- style   Style Sheets
  179.  *           |
  180.  *           |- script  Client-side Scripts (local to current directory)
  181.  *           |- style   Style sheets (local to current directory)
  182.  *
  183.  *       --- slib  Server library (Apache alias)
  184.  *           |
  185.  *           |- image   Images
  186.  *           |  |
  187.  *           |  |- brick   Link bricks
  188.  *           |  |- button  Control buttons
  189.  *           |
  190.  *           |- script  Client-side Scripts
  191.  *           |- style   Style sheets
  192.  * </pre>
  193.  *
  194.  * @category Cnz
  195.  * @package  Cnz_Html
  196.  */
  197. class Cnz_Html
  198. {
  199.     const CONFIG_SEC_HTML        'Html';
  200.     const CONFIG_SEC_DATABASE    'Database';
  201.     const CONTENT_TYPE_XHTML    'application/xhtml+xml';
  202.     const CONTENT_TYPE_HTML        'text/html';
  203.     const JAVASCRIPT_TYPE_XHTML    'application/javascript';
  204.     const JAVASCRIPT_TYPE_HTML    'text/javascript';
  205.     const STYLE_TYPE        'text/css';
  206.     const DEFAULT_BRICK_DIR        '/slib/image/brick/';
  207.     const DEFAULT_BUTTON_DIR    '/slib/image/button/';
  208.     const DEFAULT_CFG_FILE        '../cfg/html.ini';
  209.     const DEFAULT_DBCFG_FILE    '../cfg/database.ini';
  210.     const DEFAULT_CHARSET        'utf-8';
  211.     const DEFAULT_LANGUAGE        'en-us';
  212.     const DEFAULT_FIELD_DELIMITER    ':';
  213.     const DEFAULT_LIST_DELIMITER    ',';
  214.     const DEFAULT_LOG_DIR        'log';
  215.     const DEFAULT_LOG_FILE        'html.log';
  216.     const DEFAULT_LOG_LEVEL        Zend_Log::INFO;
  217.     const DEFAULT_TMP_DIR        'tmp';
  218.     const DEFAULT_UPLOAD_DIR    'upload';
  219.     const SCRIPT_FILE_EXT        'js';
  220.     const STYLE_FILE_EXT        'css';
  221.  
  222.     /**#@+ @var array */
  223.     private static $charSetArray    array(self::DEFAULT_CHARSET);
  224.     private static $languageArray    array(self::DEFAULT_LANGUAGE);
  225.     /**#@-*/
  226.  
  227.     /**#@+ @var boolean */
  228.     private static $transitionalFlag    false;
  229.     /**#@-*/
  230.  
  231.     /**#@+ @var int */
  232.     private static $logLevel    self::DEFAULT_LOG_LEVEL;
  233.     private static $indentLevel    0;
  234.     private static $phpLogLevel    NULL;
  235.     /**#@-*/
  236.  
  237.     /**#@+ @var string */
  238.     private static $brickDir    self::DEFAULT_BRICK_DIR;
  239.     private static $buttonDir    self::DEFAULT_BUTTON_DIR;
  240.     private static $logDir        self::DEFAULT_LOG_DIR;
  241.     private static $logFile        self::DEFAULT_LOG_FILE;
  242.     private static $phpLogFile    NULL;
  243.     private static $tmpDir        self::DEFAULT_TMP_DIR;
  244.     private static $uploadDir    self::DEFAULT_UPLOAD_DIR;
  245.     private static $charSet        self::DEFAULT_CHARSET;
  246.     private static $contentType    self::CONTENT_TYPE_HTML;
  247.     private static $indentString    "\t";
  248.     private static $javascriptType    self::JAVASCRIPT_TYPE_HTML;
  249.     private static $language    self::DEFAULT_LANGUAGE;
  250.     private static $htmlConfigFile    NULL;
  251.     private static $dbConfigFile    NULL;
  252.     private static $domain        NULL;
  253.     private static $sslDomain    NULL;
  254.     /** For config values with multiple parts */
  255.     private static $fieldDelimiter    self::DEFAULT_FIELD_DELIMITER;
  256.     /** For config entries with list values */
  257.     private static $listDelimiter    self::DEFAULT_LIST_DELIMITER;
  258.     private static $wcagLevel    '';
  259.     /**#@-*/
  260.  
  261.     /** @var Zend_Db_Adapter_Abstract */
  262.     private static $db        NULL;
  263.  
  264.     /** @var Zend_Log */
  265.     private static $logger        NULL;
  266.  
  267.     /* Getters/Setters ===================================================*/
  268.  
  269.     /** @return string Brick directory */
  270.     public static function getBrickDir()
  271.     {
  272.         return self::$brickDir;
  273.     }
  274.  
  275.     /** @return string Button directory */
  276.     public static function getButtonDir()
  277.     {
  278.         return self::$buttonDir;
  279.     }
  280.  
  281.     /** @return string Content type */
  282.     public static function getContentType()
  283.     {
  284.         return self::$contentType;
  285.     }
  286.  
  287.     /** @return Zend_Db Database connection */
  288.     public static function getDb()
  289.     {
  290.         return self::$db;
  291.     }
  292.  
  293.     /** @return string Domain */
  294.     public static function getDomain()
  295.     {
  296.         return self::$domain;
  297.     }
  298.  
  299.     /** @return string Config file field delimiter */
  300.     public static function getFieldDelimiter()
  301.     {
  302.         return self::$fieldDelimiter;
  303.     }
  304.  
  305.     /**
  306.      * @param  string $fieldDelimiter New config file field delimiter
  307.      * @return void 
  308.      */
  309.     public static function setFieldDelimiter($fieldDelimiter self::DEFAULT_FIELD_DELIMITER)
  310.     {
  311.         self::$fieldDelimiter $fieldDelimiter;
  312.         return;
  313.     }
  314.  
  315.     /** @return string HTML configuration file */
  316.     public static function getHtmlConfigFile()
  317.     {
  318.         return self::$htmlConfigFile;
  319.     }
  320.  
  321.     /** @return int Indent level */
  322.     public static function getIndentLevel()
  323.     {
  324.         return (int)self::$indentLevel;
  325.     }
  326.  
  327.     /**
  328.      * @param  int $indentLevel New indentation level
  329.      * @return void 
  330.      */
  331.     public static function setIndentLevel($indentLevel)
  332.     {
  333.         $i = (int)$indentLevel;
  334.         if ($i 0return;
  335.         self::$indentLevel $i;
  336.         return;
  337.     }
  338.  
  339.     /** @return string Indent string */
  340.     public static function getIndentString()
  341.     {
  342.         return self::$indentString;
  343.     }
  344.  
  345.     /** @return string Type attribute for HTML script tag */
  346.     public static function getJavascriptType()
  347.     {
  348.         return self::$javascriptType;
  349.     }
  350.  
  351.     /** @return string Language code */
  352.     public static function getLanguage()
  353.     {
  354.         return self::$language;
  355.     }
  356.  
  357.     /** @return string Config file list delimiter */
  358.     public static function getListDelimiter()
  359.     {
  360.         return self::$listDelimiter;
  361.     }
  362.  
  363.     /**
  364.      * @param  string $listDelimiter New config file list delimiter
  365.      * @return void 
  366.      */
  367.     public static function setListDelimiter($listDelimiter self::DEFAULT_LIST_DELIMITER)
  368.     {
  369.         self::$listDelimiter $listDelimiter;
  370.         return;
  371.     }
  372.  
  373.     /** @return Zend_Log Logger */
  374.     public static function getLogger()
  375.     {
  376.         return self::$logger;
  377.     }
  378.  
  379.     /** @return string SSL domain */
  380.     public static function getSslDomain()
  381.     {
  382.         return self::$sslDomain;
  383.     }
  384.  
  385.     /** @return string Tmp directory */
  386.     public static function getTmpDir()
  387.     {
  388.         return self::$tmpDir;
  389.     }
  390.  
  391.     /** @return string Upload directory */
  392.     public static function getUploadDir()
  393.     {
  394.         return self::$uploadDir;
  395.     }
  396.  
  397.     /* Testers ===========================================================*/
  398.  
  399.     /** @return boolean True if SSL */
  400.     public static function isSsl()
  401.     {
  402.         return isset($_SERVER['HTTPS']);
  403.     }
  404.  
  405.     /** @return boolean True if content type is XHTML */
  406.     public static function isXhtml()
  407.     {
  408.         return self::$contentType == self::CONTENT_TYPE_XHTML;
  409.     }
  410.  
  411.     /* Static Methods ====================================================*/
  412.  
  413.     /**
  414.      * Convert an associative array to a list of the form key:val,key:val.
  415.      * If any value is itself an array, it will be expanded as
  416.      * key:val1:val2...
  417.      *
  418.      * @param  array  $array 
  419.      * @param  string $fieldDelimiter 
  420.      * @param  string $listDelimiter 
  421.      * @return string List
  422.      */
  423.     public static function arrayToList($array$fieldDelimiter NULL$listDelimiter NULL)
  424.     {
  425.         if (empty($fieldDelimiter)) $fieldDelimiter self::$fieldDelimiter;
  426.         if (empty($listDelimiter)) $listDelimiter self::$listDelimiter;
  427.         $result '';
  428.         $n count($array);
  429.         $i 0;
  430.         foreach ($array as $key => $value)
  431.         {
  432.             $result .= $key;
  433.             if (!empty($value))
  434.             {
  435.                 if (is_array($value))
  436.                 {
  437.                     foreach ($value as $v)
  438.                     {
  439.                         $result .= $fieldDelimiter $v;
  440.                     }
  441.                 }
  442.                 else
  443.                 {
  444.                     $result .= $fieldDelimiter $value;
  445.                 }
  446.             }
  447.             if ($i++ < $n 1$result .= $listDelimiter;
  448.         }
  449.         return $result;
  450.     }
  451.  
  452.     /**
  453.      * Convert a configuration file string value to boolean.
  454.      *
  455.      * @param  $value  Value from configuration file
  456.      * @return boolean $value converted to boolean
  457.      */
  458.     public static function configFlag($value)
  459.     {
  460.         switch (strtolower($value))
  461.         {
  462.         case true:
  463.         case '1':
  464.         case 'enable':
  465.         case 'enabled':
  466.         case 'true':
  467.         case 'y';
  468.         case 'yes':
  469.             return true;
  470.             break;
  471.         }
  472.  
  473.         return false;
  474.     }
  475.  
  476.     /**
  477.      * Create a database connection using the configuration information
  478.      * provided to <kbd>init()</kbd>.  The default Zend_Db_Table_Abstract
  479.      * adapter is set to this connection.  The connection is actually
  480.      * established if nowFlag is true.
  481.      *
  482.      * @param  boolean $nowFlag Connect to database now
  483.      * @return boolean Success
  484.      */
  485.     public static function dbConnect($nowFlag false)
  486.     {
  487.         Zend_Loader::loadClass('Zend_Db');
  488.         Zend_Loader::loadClass('Zend_Db_Table');
  489.  
  490.         // Process configuration file.
  491.         $config new Zend_Config_Ini(self::$dbConfigFileself::CONFIG_SEC_DATABASE);
  492.         if (!isset($config->type)) return false;
  493.         $type strtolower($config->type);
  494.         switch ($type)
  495.         {
  496.         case 'db2':
  497.             $type 'pdo_ibm';
  498.             break;
  499.         case 'oracle':
  500.             $type 'pdo_oci';
  501.             break;
  502.         default:
  503.             $type 'pdo_' $type;
  504.             break;
  505.         }
  506.  
  507.         $options array();
  508.         if (isset($config->host)) $options['host'$config->host;
  509.         if (isset($config->port)) $options['port'$config->port;
  510.         if (!isset($config->dbname)) return false;
  511.         $options['dbname'$config->dbname;
  512.         if (isset($config->username)) $options['username'$config->username;
  513.         if (isset($config->password)) $options['password'$config->password;
  514.  
  515.         // Create the connection
  516.         try
  517.         {
  518.             self::$db Zend_Db::factory($type$options);
  519.             if ($nowFlagself::$db->getConnection();
  520.             Zend_Db_Table::setDefaultAdapter(self::$db);
  521.         }
  522.         catch (Zend_Exception $e)
  523.         {
  524.             self::$logger->err(__METHOD__ . '[' . __LINE__ . '] ' 'Exception from ' get_class($e':  ' $e->getMessage('.');
  525.             return false;
  526.         }
  527.  
  528.         return true;
  529.     }
  530.  
  531.     /**
  532.      * Check file extension.
  533.      *
  534.      * @param  string $filename 
  535.      * @param  string $ext 
  536.      * @return mixed Filename without extension, or false if wrong file extension
  537.      */
  538.     public static function checkFileExtension($filename$ext)
  539.     {
  540.         $dotPos strrpos($filename'.');
  541.         if ($dotPos === falsereturn '';
  542.         $fileExt substr($filename$dotPos 1);
  543.         if ($fileExt != $extreturn false;
  544.         return substr($filename0$dotPos);
  545.     }
  546.  
  547.     /**
  548.      * Display W3C bricks for valid X/HTML, CSS, and WCAG.
  549.      *
  550.      * The files valid-xhtml11.png, valid-html401.png, and vcss.png (all
  551.      * available from w3.org) must be in brickDir.
  552.      *
  553.      * @param  boolean $link Link to validator pages (unless SSL)
  554.      * @return void 
  555.      */
  556.     public static function displayW3cBricks($link true)
  557.     {
  558.         // If SSL, disable links because there will be no referrer.
  559.         if (isset($_SERVER['HTTPS'])) $link false;
  560.  
  561.             if ($linkecho '<a href = "http://www.citadelnetwork.com/open/php/cnzframework/">';
  562.             echo '<img alt = "[CNZ Framework]" src = "' self::$brickDir 'cnzframework.png" style = "border-style:none; height:31px; margin-right:5px; width:88px;"/>';
  563.             if ($linkecho '</a>';
  564.  
  565.         if (self::$contentType == self::CONTENT_TYPE_XHTML)
  566.         {
  567.             if ($linkecho '<a href = "http://validator.w3.org/check?uri=referer">';
  568.             if (self::$transitionalFlagecho '<img alt = "[Valid XHTML 1.0]" src = "' self::$brickDir 'valid-xhtml10.png" style = "border-style:none; height:31px; width:88px;"/>';
  569.             else echo '<img alt = "[Valid XHTML 1.1]" src = "' self::$brickDir 'valid-xhtml11.png" style = "border-style:none; height:31px; width:88px;"/>';
  570.             if ($linkecho '</a>';
  571.         }
  572.         else
  573.         {
  574.             if ($linkecho '<a href = "http://validator.w3.org/check?uri=referer">';
  575.             echo '<img alt = "[Valid HTML 4.01 Strict]" src = "' self::$brickDir 'valid-html401.png" style = "border-style:none; height:31px; width:88px;"/>';
  576.             if ($linkecho '</a>';
  577.         }
  578.         if ($linkecho '<a href = "http://jigsaw.w3.org/css-validator/check/referer">';
  579.         echo '<img alt = "[Valid CSS]" src = "' self::$brickDir 'vcss.png" style = "border-style:none; height:31px; width:88px;"/>';
  580.         if ($linkecho '</a>';
  581.  
  582.         if (!empty(self::$wcagLevel))
  583.         {
  584.             if ($linkecho '<a href = "http://www.w3.org/WAI/WCAG1'self::$wcagLevel'-Conformance">';
  585.             echo '<img alt = "[WCAG Level 'self::$wcagLevel' Conformance]" src = "' self::$brickDir 'wcag1'self::$wcagLevel'.gif" style = "border-style:none; height:31px; width:88px;"/>';
  586.             if ($linkecho '</a>';
  587.         }
  588.  
  589.         return;
  590.     }
  591.  
  592.     /**
  593.      * Determine the current document directory.  This is necessary for use
  594.      * with mod_rewrite, when the script directory cannot be relied on.
  595.      *
  596.      * @param  relative Relative (to web doc root) flag
  597.      * @return string Root URL
  598.      */
  599.     public static function