Advertisement
Guest User

Untitled

a guest
Mar 7th, 2012
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 27.26 KB | None | 0 0
  1. <?php
  2. /*
  3.  * File:        c-css.php
  4.  * CVS:         $Id$
  5.  * Description: Conditional CSS parser
  6.  * Author:      Allan Jardine
  7.  * Created:     Sun May 20 14:05:46 GMT 2007
  8.  * Modified:    $Date$ by $Author$
  9.  * Language:    PHP
  10.  * License:     CDDL v1.0
  11.  * Project:     COnditional-CSS
  12.  *
  13.  * Copyright 2007-2008 Allan Jardine, all rights reserved.
  14.  *
  15.  * This source file is free software, under the U4EA Common Development and
  16.  * Distribution License (U4EA CDDL) v1.0 only, as supplied with this software.
  17.  * This license is also available online:
  18.  *   http://www.sprymedia.co.uk/license/u4ea_cddl
  19.  *
  20.  * This source file is distributed in the hope that it will be useful, but
  21.  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  22.  * or FITNESS FOR A PARTICULAR PURPOSE. See the CDDL for more details.
  23.  *
  24.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  25.  * DESCRIPTION
  26.  *
  27.  * c-css is a program which allows IE style conditional comments to be
  28.  * inserted inline with CSS statements, and then be parsed out as required
  29.  * for individual web browsers. This allows easy targeting of styles to
  30.  * different browsers, and different versions of browsers as required by the
  31.  * developer, such that browser CSS bugs can be easily over come.
  32.  *
  33.  * The bowsers which are currently supported are:
  34.  *   Internet Explorer (v2 up) - IE
  35.  *   Internet Explorer Mac - IEMac
  36.  *   Gecko (Firefox etc) - Gecko
  37.  *   Webkit (Safari etc) - Webkit
  38.  *   Opera - Opera
  39.  *   Konqueror - Konq
  40.  *   Safari Mobile (iPhone, iPod) - SafMob
  41.  *   IE Mobile - IEmob
  42.  *   PSP Web browser - PSP
  43.  *   NetFront - NetF
  44.  *
  45.  * The syntax used for the conditional comments is:
  46.  *   [if {!} {browser}]
  47.  *   [if {!} {browser_group}]
  48.  *   [if {!} {browser} {version}]
  49.  *   [if {!} {condition} {browser} {version}]
  50.  *
  51.  * Examples:
  52.  *   [if ! Gecko]#column_right {
  53.  *     [if cssA]float:left;
  54.  *     width:250px;
  55.  *     [if Webkit] opacity: 0.8;
  56.  *     [if IE 6] ie6: 100%;
  57.  *     [if lt IE 6] lt-ie6: 100%;
  58.  *     [if lte IE 6] lte-ie6: 100%;
  59.  *     [if eq IE 6] eq-ie6: 100%;
  60.  *     [if gte IE 6] gte-ie6: 100%;
  61.  *     [if gt IE 6] gt-ie6: 100%;
  62.  *     [if ! lte IE 6] not-lte-ie6: 100%;
  63.  *   }
  64.  *
  65.  * As can be seen from above a conditional comment can be applied to either
  66.  * a whole CSS block, or to individual rules.
  67.  *
  68.  * Note that ___VAR___ type variables are used for the Conditional-CSS online compiler - it's safe
  69.  * to either ignore these or simply remove them.
  70.  */
  71.  
  72.  
  73.  
  74.  
  75. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  76.  * Class and interface declerations
  77.  */
  78.  
  79.  
  80. /*
  81.  * Interface: ccss
  82.  * Purpose:   'Prototype' functions for API
  83.  * Notes:     See the implemention header comment for the purpose etc
  84.  */
  85. interface ifCcss
  86. {
  87.     /* Recommended public functions */
  88.     public function fnComplete ();
  89.    
  90.     /* Other public functions */
  91.     public function fnAddFiles ();
  92.     public function fnReadCSSFiles ();
  93.     public function fnCssIncludes ();
  94.     public function fnStripComments ();
  95.     public function fnProcess ();
  96.     public function fnOutput ();
  97.     public function fnOutputHeader ();
  98.     public function fnSetUserBrowser ();
  99.     public function fnSetUserBrowserGET ();
  100.     public function fnSwitches ();
  101.     public function fnOutputUsage(  );
  102.     public function fnSetBrowserGroup ( $aGroups );
  103. }
  104.  
  105.  
  106. /*
  107.  * Class:   ccss
  108.  * Purpose: Preform c-css parsing
  109.  */
  110. class ccss implements ifCcss
  111. {
  112.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  113.      * Public variables
  114.      */
  115.    
  116.     /*
  117.      * Variable: array string:aCssFiles
  118.      * Purpose:  Always include files
  119.      * Scope:    ccss
  120.      * Notes:    Define your CSS files to be included here. Remember that  
  121.      *   Conditional-CSS will automatically expand @import statements into the
  122.      *   full css file. For  example:
  123.      *     $aCssFiles = array( 'site.css', 'fonts.css' );
  124.      */
  125.     public $aCssFiles = array(
  126.      
  127.     );
  128.    
  129.    
  130.     /*
  131.      * Variable: array array:aGroups
  132.      * Purpose:  Browser group definitions
  133.      * Scope:    ccss
  134.      * Notes:    Browsers can be groups together such that a  single conditional
  135.      *   statement can refer to multiple browsers. For example 'cssA' might be
  136.      *   top level css support
  137.      *   The sub arrays must have the following information:
  138.      *      string:sGrade - CSS group name for easy groupng of statements
  139.      *      string:sEngine - Engine name (used in the conditional statements)
  140.      *      int:iGreaterOrEqual - whether the statements should apply for the browser
  141.      *        version greater (1) or less (0) that the given version
  142.      *      float:dVersion - The engine version for the condition of this group
  143.      */
  144.     public $aGroups = array(
  145.         array(
  146.             'sGrade'=>'cssA',
  147.             'sEngine'=>'IE',    
  148.             'iGreaterOrEqual'=>1,
  149.             'dVersion'=>6 ), /* IE 6 and up */
  150.         array(
  151.             'sGrade'=>'cssA',
  152.             'sEngine'=>'Gecko',  
  153.             'iGreaterOrEqual'=>1,
  154.             'dVersion'=>1.0 ), /* Mozilla 1.0 and up */
  155.         array(
  156.             'sGrade'=>'cssA',
  157.             'sEngine'=>'Webkit',
  158.             'iGreaterOrEqual'=>1,
  159.             'dVersion'=>312 ), /* Safari 1.3 and up  */
  160.         array(
  161.             'sGrade'=>'cssA',
  162.             'sEngine'=>'SafMob',
  163.             'iGreaterOrEqual'=>1,
  164.             'dVersion'=>312 ), /* All Mobile Safari  */
  165.         array(
  166.             'sGrade'=>'cssA',
  167.             'sEngine'=>'Opera',  
  168.             'iGreaterOrEqual'=>1,
  169.             'dVersion'=>7 ), /* Opera 7 and up */
  170.         array(
  171.             'sGrade'=>'cssA',
  172.             'sEngine'=>'Konq',  
  173.             'iGreaterOrEqual'=>1,
  174.             'dVersion'=>3.3 ), /* Konqueror 3.3 and up  */
  175.         array(
  176.             'sGrade'=>'cssX',
  177.             'sEngine'=>'IE',    
  178.             'iGreaterOrEqual'=>0,
  179.             'dVersion'=>4   ), /* IE 4 and down */
  180.         array(
  181.             'sGrade'=>'cssX',
  182.             'sEngine'=>'IEMac',  
  183.             'iGreaterOrEqual'=>0,
  184.             'dVersion'=>4.5 )  /* IE Mac 4 and down */
  185.     );
  186.    
  187.    
  188.     /*
  189.      * Variable: string:sVersion
  190.      * Purpose:  version information {major.minor.language.bugfix}
  191.      * Scope:    ccss - public
  192.      */
  193.     public $sVersion = '1.2.php.4';
  194.    
  195.    
  196.     /*
  197.      * Variable: string:sUserBrowser
  198.      * Purpose:  Store the target browser
  199.      * Scope:    ConditionalCSS.CCss - public
  200.      */
  201.     public $sUserBrowser = "";
  202.    
  203.    
  204.     /*
  205.      * Variable: string:dUserVersion
  206.      * Purpose:  Store the target browser version
  207.      * Scope:    ConditionalCSS.CCss - public
  208.      */
  209.     public $sUserVersion = 0;
  210.    
  211.    
  212.     /*
  213.      * Variable: string:sUserGroup
  214.      * Purpose:  Store the target group
  215.      * Scope:    ConditionalCSS.CCss - public
  216.      */
  217.     public $sUserGroup = "";
  218.    
  219.    
  220.     /*
  221.      * Variable: string:sUserAgent
  222.      * Purpose:  Store the target user agent string
  223.      * Scope:    ConditionalCSS.CCss - public
  224.      */
  225.     public $sUserAgent = "";
  226.    
  227.    
  228.     /*
  229.      * Variable: string:sAuthor
  230.      * Purpose:  Author information for the CSS file for inclusion in the header
  231.      * Scope:    ConditionalCSS.CCss - public
  232.      */
  233.     public $sAuthor = /* ___AUTHOR___ */  "";
  234.    
  235.    
  236.     /*
  237.      * Variable: string:sCopyright
  238.      * Purpose:  Copyright information for the CSS file for inclusion in the header
  239.      * Scope:    ConditionalCSS.CCss - public
  240.      */
  241.     public $sCopyright = /* ___COPYRIGHT___ */ "";
  242.    
  243.    
  244.    
  245.    
  246.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  247.      * Private variables
  248.      */
  249.    
  250.     /*
  251.      * Variable: array string:asCSSFiles
  252.      * Purpose:  CSS files to be read
  253.      * Scope:    ccss - private
  254.      */
  255.     private $_asCSSFiles;
  256.    
  257.     /*
  258.      * Function: string:_sCSS
  259.      * Purpose:  css buffer
  260.      * Scope:    ccss - private
  261.      */
  262.     private $_sCSS = '';
  263.    
  264.    
  265.    
  266.    
  267.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  268.      * Public methods
  269.      */
  270.    
  271.     /*
  272.      * Function: __construct
  273.      * Purpose:  ccss constructor
  274.      * Returns:  -
  275.      * Inputs:   string:... - any number of string variables pointing to files
  276.      */
  277.     function __construct ()
  278.     {
  279.         // If the object is created with arguments, store them as files
  280.         $this->_asCSSFiles = func_get_args();
  281.     }
  282.    
  283.    
  284.     /*
  285.      * Function: fnComplete
  286.      * Purpose:  Perform a standard Conditional-CSS parsing run on input files
  287.      * Returns:  -
  288.      * Inputs:   -
  289.      * Notes:    You might want to customise this function or use the public functions to create
  290.      *   your own processing functionality
  291.      */
  292.     public function fnComplete ()
  293.     {
  294.         /* Get the 'main' arguments */
  295.         global $argv;
  296.         global $argc;
  297.        
  298.         /*
  299.          * Set up the required variables based on input
  300.          */
  301.         $this->fnSetUserBrowserGET();   /* Allow GET vars */
  302.         $iOptind = $this->fnSwitches(); /* CLI switches */
  303.         $this->fnSetUserBrowser();
  304.         $this->fnSetBrowserGroup( $this->aGroups );
  305.        
  306.         $this->fnOutputHeader();
  307.        
  308.         /*
  309.          * Add files
  310.          */
  311.         for ( $i=$iOptind ; $i<$argc ; $i++ )
  312.         {
  313.             $this->fnAddFiles( $argv[$i] );
  314.         }
  315.        
  316.         for ( $i=0 ; $i<count($this->aCssFiles) ; $i++ )
  317.         {
  318.             $this->fnAddFiles( $this->aCssFiles[$i] );
  319.         }
  320.        
  321.         /*
  322.          * Read all required files
  323.          */
  324.         $this->fnReadCSSFiles();
  325.         $this->fnCssIncludes();
  326.         /*
  327.          * Do the c-css magic on the imported files
  328.          */
  329.         $this->fnProcess();
  330.         $this->fnOutput();
  331.     }
  332.    
  333.    
  334.     /*
  335.      * Function: fnAddFiles
  336.      * Purpose:  add new files to be processed
  337.      * Returns:  -
  338.      * Inputs:   string:... - any number of string variables pointing to files
  339.      */
  340.     public function fnAddFiles ()
  341.     {
  342.         for ( $i=0 ; $i<func_num_args() ; $i++ )
  343.         {
  344.             $this->_asCSSFiles[] = func_get_arg( $i );
  345.         }
  346.     }
  347.    
  348.    
  349.     /*
  350.      * Function: fnReadCSSFiles
  351.      * Purpose:  Read the CSS files
  352.      * Returns:  -
  353.      * Inputs:   string:... - any number of string variables pointing to files
  354.      */
  355.     public function fnReadCSSFiles ()
  356.     {
  357.         $this->_sCSS = '';
  358.         for ( $i=0 ; $i<count($this->_asCSSFiles) ; $i++ )
  359.         {
  360.             $this->_sCSS .= $this->_fnReadCSSFile( $this->_asCSSFiles[$i] );
  361.         }
  362.     }
  363.    
  364.    
  365.     /*
  366.      * Function: fnCssIncludes
  367.      * Purpose:  Check the input for @import statements and include files found
  368.      * Returns:  -
  369.      * Inputs:   -
  370.      */
  371.     public function fnCssIncludes ()
  372.     {
  373.         // First remove any comments as they could get in the way
  374.         $this->fnStripComments();
  375.        
  376.         // Find all conditional @import statements
  377.         while ( preg_match( '/\[if .*?\]\s*?@import .*?;/s', $this->_sCSS, $aMatch ) )
  378.         {
  379.             preg_match( "/\[if .*?\]/", $aMatch[0], $aCCBlock );
  380.             $sImport = trim( preg_replace( "/\[if .*?\]/", "", $aMatch[0] ) );
  381.            
  382.             $this->fnCssImport( $sImport, $this->_fnCheckCC( $aCCBlock[0] ), $aMatch[0] );
  383.             unset ( $aMatch );
  384.         }
  385.        
  386.         // Find all non-conditional @import statements
  387.         while ( preg_match( '/@import .*?;/s', $this->_sCSS, $aMatch ) )
  388.         {
  389.             $this->fnCssImport( $aMatch[0], 1, $aMatch[0] );
  390.             unset ( $aMatch );
  391.         }
  392.     }
  393.    
  394.    
  395.     /*
  396.      * Function: fnCssImport
  397.      * Purpose:  Deal with an import CSS file
  398.      * Returns:  -
  399.      * Inputs:   string:sImportStatement - @import...
  400.      *           int:iImport - include the file or not
  401.      *           string:sFullImport - The full string to remove
  402.      */
  403.     public function fnCssImport ( $sImportStatement, $iImport, $sFullImport )
  404.     {
  405.         if ( $iImport == 1 )
  406.         {
  407.             // Parse @import to get the URL
  408.             $sCSSFile = $this->_fnParseImport( $sImportStatement );
  409.            
  410.             // Read the CSS file
  411.             $sTmpCSS = $this->_fnReadCSSFile( $sCSSFile );
  412.            
  413.             // Save it back into the main css string
  414.             $this->_sCSS = str_replace( $sFullImport, $sTmpCSS, $this->_sCSS );
  415.            
  416.             // Remove comments to ease parsing
  417.             $this->fnStripComments();
  418.         }
  419.         else
  420.         {
  421.             /* Remove the import statement */
  422.             $this->_sCSS = str_replace( $sFullImport, "", $this->_sCSS );
  423.         }
  424.     }
  425.    
  426.    
  427.     /*
  428.      * Function: fnStripComments
  429.      * Purpose:  Strip multi-line comments from the target css
  430.      * Returns:  -
  431.      * Inputs:   -
  432.      */
  433.     public function fnStripComments ()
  434.     {
  435.         $this->_sCSS = preg_replace ( '/\/\*.*?\*\//s', "", $this->_sCSS );
  436.     }
  437.    
  438.    
  439.     /*
  440.      * Function: fnProcess
  441.      * Purpose:  Strip multi-line comments from the target css
  442.      * Returns:  -
  443.      * Inputs:   -
  444.      */
  445.     public function fnProcess ()
  446.     {
  447.         // Break the CSS down into blocks
  448.         // Match all blacks - with or without nested blocks
  449.         preg_match_all( "/.*?\{((?>[^{}]*)|(?R))*\}/s", $this->_sCSS, $aCSSBlock );
  450.        
  451.         for ( $i=0 ; $i<count($aCSSBlock[0]) ; $i++ )
  452.         {
  453.             $iProcessBlock = 1;
  454.             $sBlock = $aCSSBlock[0][$i];
  455.            
  456.             // Find if the block has a conditional comment
  457.             if ( preg_match( "/\[if .*?\].*?\{/s", $sBlock ) )
  458.             {
  459.                 preg_match( "/\[if .*?\]/", $sBlock, $aCCBlock );
  460.                
  461.                 // Find out if the block should be included or not
  462.                 if ( $this->_fnCheckCC ( $aCCBlock[0] ) == 0 )
  463.                 {
  464.                     $iProcessBlock = 0;
  465.                    
  466.                     // Drop the block from the output string
  467.                     $this->_sCSS = str_replace ( $aCSSBlock[0][$i], "", $this->_sCSS );
  468.                 }
  469.                 // If it should be then remove the conditional comment from the start
  470.                 // of the block
  471.                 else
  472.                 {
  473.                     $sBlock = preg_replace( "/\[if .*?\]/", "", $sBlock, 1 );  
  474.                 }
  475.             }
  476.            
  477.             // If the block should be processed
  478.             if ( $iProcessBlock == 1 )
  479.             {
  480.                 // Loop over the block looking for conditional comment statements
  481.                 while ( preg_match( "/\[if .*?\]/", $sBlock, $aCSSRule ) )
  482.                 {
  483.                     // See if statement should be included or not
  484.                     if ( $this->_fnCheckCC( $aCSSRule[0] ) == 0 )
  485.                     {
  486.                         // Remove statement - note that this might remove the trailing
  487.                         // } of the block! This is valid css as the last statement is
  488.                         // implicitly closed by the }. So we moke sure there is one at the
  489.                         // end later on
  490.                         $sBlock = preg_replace( '/\[if .*?\].*?(;|\})/s', "", $sBlock, 1 );
  491.                     }
  492.                     // Include statement
  493.                     else
  494.                     {
  495.                         // Remove CC
  496.                         $sBlock = preg_replace( "/\[if .*?\]/", "", $sBlock, 1 );
  497.                     }
  498.                 }
  499.                
  500.                 // Ensure the block has a closing }
  501.                 if ( preg_match ( '/\}$/', $sBlock ) == 0 )
  502.                 {
  503.                     $sBlock .= "}";
  504.                 }
  505.                
  506.                 // Write the modifed block back into the CSS string
  507.                 $this->_sCSS = str_replace( $aCSSBlock[0][$i], $sBlock, $this->_sCSS );
  508.             }
  509.         }
  510.     }
  511.    
  512.    
  513.     /*
  514.      * Function: fnOutput
  515.      * Purpose:  Remove extra white space and output
  516.      * Returns:  -
  517.      * Inputs:   -
  518.      */
  519.     public function fnOutput ()
  520.     {
  521.         // Remove the white space in the css - while preserving the needed spaces
  522.         $this->_sCSS = preg_replace( '/\s/s', ' ', trim($this->_sCSS) );
  523.         while ( preg_match ( '/  /', $this->_sCSS ) )
  524.         {
  525.             $this->_sCSS = preg_replace( '/  /', ' ', $this->_sCSS );
  526.         }
  527.        
  528.         // Add new lines for basic legibility
  529.         $this->_sCSS = preg_replace( '/} /', "}\n", $this->_sCSS );
  530.        
  531.         // Phew - we finally got there...
  532.         echo $this->_sCSS;
  533.         echo "\n";
  534.     }
  535.    
  536.    
  537.     /*
  538.      * Function: fnOutputHeader
  539.      * Purpose:  Header output with information
  540.      * Returns:  -
  541.      * Inputs:   -
  542.      */
  543.     public function fnOutputHeader ()
  544.     {
  545.         // Give a CSS MIME type so the browser knows this is a css file
  546.         header('Content-type: text/css');
  547.        
  548.         // Add comment to output
  549.         echo "/*\n";
  550.         echo " * c-css by U4EA Technologies - Allan Jardine\n";
  551.         echo " * Version:       ".$this->sVersion."\n";
  552.        
  553.         if ( $this->sAuthor != "" )
  554.         {
  555.         echo " * CSS Author:    ".$this->sAuthor."\n";
  556.         }
  557.        
  558.         if ( $this->sCopyright != "" )
  559.         {
  560.         echo " * Copyright:     ".$this->sCopyright."\n";
  561.         }
  562.        
  563.         echo " * Browser:       ".$this->sUserBrowser." ".$this->sUserVersion."\n";
  564.         echo " * Browser group: ".$this->sUserGroup."\n";
  565.         echo " */\n";
  566.        
  567.     /* X grade CSS means the browser doesn't see the CSS at all */
  568.         if ( $this->sUserGroup == "cssX" )
  569.         {
  570.             exit(0);
  571.         }
  572.     }
  573.    
  574.    
  575.     /*
  576.      * Function: fnSetUserBrowser
  577.      * Purpose:  Set the user's browser information
  578.      * Returns:  -
  579.      * Inputs:   -
  580.      */
  581.     public function fnSetUserBrowser ()
  582.     {
  583.         /* Check we are not overriding a CLI or GET set of the browser */
  584.         if ( $this->sUserBrowser != ""  )
  585.         {
  586.             return;
  587.         }
  588.        
  589.         if ( $this->sUserAgent == "" )
  590.         {
  591.             $this->sUserAgent = $_SERVER['HTTP_USER_AGENT'];
  592.         }
  593.        
  594.        
  595.         // Safari Mobile
  596.         if ( preg_match( '/mozilla.*applewebkit\/([0-9a-z\+\-\.]+).*mobile.*/si', $this->sUserAgent, $aUserAgent ) )
  597.         {
  598.             $this->sUserBrowser = "SafMob";
  599.             $this->sUserVersion = $aUserAgent[1];
  600.         }
  601.        
  602.         // Webkit (Safari, Shiira etc)
  603.         else if ( preg_match( '/mozilla.*applewebkit\/([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  604.         {
  605.             $this->sUserBrowser = "Webkit";
  606.             $this->sUserVersion = $aUserAgent[1];
  607.         }
  608.        
  609.         // Opera
  610.         else if ( preg_match( '/mozilla.*opera ([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent )
  611.           || preg_match( '/^opera\/([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  612.         {
  613.             $this->sUserBrowser = "Opera";
  614.             $this->sUserVersion = $aUserAgent[1];
  615.     }
  616.        
  617.         // Gecko (Firefox, Mozilla, Camino etc)
  618.         else if ( preg_match( '/mozilla.*rv:([0-9a-z\+\-\.]+).*gecko.*/si', $this->sUserAgent, $aUserAgent ) )
  619.         {
  620.             $this->sUserBrowser = "Gecko";
  621.             $this->sUserVersion = $aUserAgent[1];
  622.         }
  623.        
  624.     // IE Mac
  625.         else if( preg_match( '/mozilla.*MSIE ([0-9a-z\+\-\.]+).*Mac.*/si', $this->sUserAgent, $aUserAgent ) )
  626.         {
  627.             $this->sUserBrowser = "IEMac";
  628.             $this->sUserVersion = $aUserAgent[1];
  629.         }
  630.        
  631.     // MS mobile
  632.         else if( preg_match( '/PPC.*IEMobile ([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  633.         {
  634.             $this->sUserBrowser = "IEMob";
  635.             $this->sUserVersion = "1.0";
  636.         }
  637.        
  638.         // MSIE
  639.         else if( preg_match( '/mozilla.*?MSIE ([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  640.         {
  641.             $this->sUserBrowser = "IE";
  642.             $this->sUserVersion = $aUserAgent[1];
  643.         }
  644.        
  645.         // Konqueror
  646.         else if( preg_match( '/mozilla.*konqueror\/([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  647.         {
  648.             $this->sUserBrowser = "Konq";
  649.             $this->sUserVersion = $aUserAgent[1];
  650.         }
  651.        
  652.         // PSP
  653.         else if( preg_match( '/mozilla.*PSP.*; ([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  654.         {
  655.             $this->sUserBrowser = "PSP";
  656.             $this->sUserVersion = $aUserAgent[1];
  657.         }
  658.        
  659.         // NetFront
  660.         else if( preg_match( '/mozilla.*NetFront\/([0-9a-z\+\-\.]+).*/si', $this->sUserAgent, $aUserAgent ) )
  661.         {
  662.             $this->sUserBrowser = "NetF";
  663.             $this->sUserVersion = $aUserAgent[1];
  664.         }
  665.        
  666.        
  667.         // Round the version number to one decimal place
  668.         $iDot = strpos( $this->sUserVersion, '.' );
  669.         if ( $iDot > 0 )
  670.         {
  671.             $this->sUserVersion = substr( $this->sUserVersion, 0, $iDot+2 );
  672.         }
  673.     }
  674.    
  675.    
  676.     /*
  677.      * Function: fnSetUserBrowserGET
  678.      * Purpose:  Set the user's browser information based on GET vars is there
  679.      *   are any
  680.      * Returns:  -
  681.      * Inputs:   -
  682.      */
  683.     public function fnSetUserBrowserGET ()
  684.     {
  685.         if ( isset( $_GET['b'] ) )
  686.         {
  687.             $this->sUserBrowser = $_GET['b'];
  688.         }
  689.        
  690.         if ( isset( $_GET['browser'] ) )
  691.         {
  692.             $this->sUserBrowser = $_GET['browser'];
  693.         }
  694.        
  695.         if ( isset( $_GET['v'] ) )
  696.         {
  697.             $this->sUserVersion = $_GET['v'];
  698.         }
  699.        
  700.         if ( isset( $_GET['version'] ) )
  701.         {
  702.             $this->sUserVersion = $_GET['version'];
  703.         }
  704.        
  705.         if ( isset( $_GET['a'] ) )
  706.         {
  707.             $this->sAuthor = $_GET['a'];
  708.         }
  709.        
  710.         if ( isset( $_GET['author'] ) )
  711.         {
  712.             $this->sAuthor = $_GET['author'];
  713.         }
  714.        
  715.         if ( isset( $_GET['c'] ) )
  716.         {
  717.             $this->sCopyright = $_GET['c'];
  718.         }
  719.        
  720.         if ( isset( $_GET['copyright'] ) )
  721.         {
  722.             $this->sCopyright = $_GET['copyright'];
  723.         }
  724.     }
  725.    
  726.    
  727.     /*
  728.      * Function: fnSwitches
  729.      * Purpose:  Deal with command line switches
  730.      * Returns:  int:i - Where the sitches end in argc/v
  731.      * Inputs:   -
  732.      * Notes:    This is a short hand method to make this script look use
  733.      *   the same cli options as the 'c' version of this program. It won't do
  734.      *   well with dodgy input - but it's not expected to be used to much.
  735.      */
  736.     public function fnSwitches ()
  737.     {
  738.         global $argc;
  739.         global $argv;
  740.        
  741.         for ( $i=1 ; $i<$argc ; $i++ )
  742.         {
  743.             if ( $argv[$i][0] == "-" )
  744.             {
  745.                 if ( $argv[$i][1] == "b" )
  746.                 {
  747.                     $i++;
  748.                     $this->sUserBrowser = $argv[$i];
  749.                 }
  750.                 else if ( $argv[$i][1] == "v" )
  751.                 {
  752.                     $i++;
  753.                     $this->sUserVersion = $argv[$i];
  754.                 }
  755.                 else if ( $argv[$i][1] == "u" )
  756.                 {
  757.                     $i++;
  758.                     $this->sUserAgent = $argv[$i];
  759.                 }
  760.                 else if ( $argv[$i][1] == "a" )
  761.                 {
  762.                     $i++;
  763.                     $this->sAuthor = $argv[$i];
  764.                 }
  765.                 else if ( $argv[$i][1] == "c" )
  766.                 {
  767.                     $i++;
  768.                     $this->sCopyright = $argv[$i];
  769.                 }
  770.                 else if ( $argv[$i][1] == "h" )
  771.                 {
  772.                     $this->fnOutputUsage();
  773.                     exit(0);
  774.                 }
  775.             }
  776.             else
  777.             {
  778.                 return $i;
  779.             }
  780.         }
  781.        
  782.         return 1;
  783.     }
  784.    
  785.    
  786.     /*
  787.      * Function: fnOutputUsage()
  788.      * Purpose:  Output the usage to the user
  789.      * Returns:  void
  790.      * Inputs:   void
  791.      */
  792.     public function fnOutputUsage(  )
  793.     {
  794.       printf (
  795.          "Usage: php c-css.php [OPTIONS]... [FILE]...\n"
  796.         ."Parse a CSS file which contains IE style conditional comments into a\n"
  797.         ."stylesheet which is specifically suited for a particular web-browser.\n"
  798.         ."\n"
  799.         ." -a     Set the stylesheet's author name for the information header.\n"
  800.         ." -b     Use this particular browser. Requires that the \n"
  801.         ."        browser version must also be set, -v. Options are:\n"
  802.         ."          IE\n"
  803.         ."          IEMac\n"
  804.         ."          Gecko\n"
  805.         ."          Webkit\n"
  806.         ."          Opera\n"
  807.         ."          Konq\n"
  808.         ."          NetF\n"
  809.         ."          PSP\n"
  810.         ." -c     Set the copyright header for the information header.\n"
  811.         ." -h     This help information.\n"
  812.         ." -u     Browser user agent string.\n"
  813.         ." -v     Use this particular browser version. Requires that\n"
  814.         ."        the browser must also be set using -b.\n"
  815.         ."\n"
  816.         ."The resulting stylesheet will be printed to stdout. Note that expected\n"
  817.         ."usage for this PHP version of c-css is through the standard PHP\n"
  818.         ."interpreter, rather than the CLI.\n"
  819.         ."\n"
  820.         ."Example usage:\n"
  821.         ." php c-css.php -b IE -v 6 example.css\n"
  822.         ."        Parse a style sheet for Internet Explorer v6\n"
  823.         ."\n"
  824.         ." php c-css.php -b Webkit -v 897 demo1.css demo2.css\n"
  825.         ."        Parse two style sheets for Webkit (Safari) v897\n"
  826.         ."\n"
  827.         ." php c-css.php -u \"Mozilla/4.0 (compatible; MSIE 5.5;)\" example.css\n"
  828.         ."        Parse stylesheet for the specified user agent string\n"
  829.         ."\n"
  830.         ."Report bugs to <software@sprymedia.co.uk>\n"
  831.         ."\n"
  832.       );
  833.     }
  834.    
  835.    
  836.     /*
  837.      * Function: fnSetBrowserGroup
  838.      * Purpose:  Based on the browser grouping we set a short hand method for
  839.      *   access
  840.      * Returns:  void
  841.      * Inputs:   array:aGroups - group information
  842.      */
  843.     public function fnSetBrowserGroup ( $aGroups )
  844.     {
  845.         for ( $i=0 ; $i<count($aGroups) ; $i++ )
  846.         {
  847.             if ( $aGroups[$i]['sEngine'] == $this->sUserBrowser )
  848.             {
  849.                 if ( $aGroups[$i]['iGreaterOrEqual'] == 1 &&
  850.                      $aGroups[$i]['dVersion'] <= $this->sUserVersion )
  851.                 {
  852.                     $this->sUserGroup = $aGroups[$i]['sGrade'];
  853.                     break;
  854.                 }
  855.                 else if ( $aGroups[$i]['iGreaterOrEqual'] == 0 &&
  856.                           $aGroups[$i]['dVersion'] >= $this->sUserVersion )
  857.                 {
  858.                     $this->sUserGroup = $aGroups[$i]['sGrade'];
  859.                     break;
  860.                 }
  861.             }
  862.         }
  863.     }
  864.    
  865.    
  866.    
  867.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  868.      * Private methods
  869.      */
  870.    
  871.     /*
  872.      * Function: _fnReadCSSFile
  873.      * Purpose:  Read a CSS file
  874.      * Returns:  array string: aCSS - the contents of the css file
  875.      * Inputs:   string:sPath - the file name and path to be read
  876.      */
  877.     private function _fnReadCSSFile ( $sPath )
  878.     {
  879.         // We use output buffering here to read the required file using 'readfile'
  880.         // as this allows us to over come some of the problems when safe mode is
  881.         // turned on
  882.         if ( is_file( $sPath ) )
  883.         {
  884.             ob_start();
  885.             readfile( $sPath );
  886.             $sCSS = ob_get_contents();
  887.             ob_end_clean();
  888.            
  889.             // If there is a hash-bang line - strip it out for compatability with C
  890.             $sCSS = preg_replace( '/^(#!.*?\n)/', '', $sCSS, 1 );
  891.            
  892.             return $sCSS;
  893.         }
  894.         else
  895.         {
  896.             echo "/*** Warning: The file $sPath could not be found ***/\n";
  897.         }
  898.     }
  899.    
  900.    
  901.     /*
  902.      * Function: _fnParseImport
  903.      * Purpose:  Get the import URI from the import statement
  904.      * Returns:  string:  - Import URL
  905.      * Inputs:   string:sImport - @import CSS statement
  906.      */
  907.     private function _fnParseImport ( $sImport )
  908.     {
  909.         $aImport = explode ( " ", $sImport );
  910.         $sURL = trim($aImport[1]);
  911.        
  912.         if ( substr($sURL, 0, 3) == "url" )
  913.         {
  914.             $sURL = substr( $sURL, 3 );
  915.         }
  916.         $sURL = str_replace ( "(", "", $sURL );
  917.         $sURL = str_replace ( ")", "", $sURL );
  918.         $sURL = str_replace ( "'", "", $sURL );
  919.         $sURL = str_replace ( '"', "", $sURL );
  920.         $sURL = str_replace ( ';', "", $sURL );
  921.         return $sURL;
  922.     }
  923.    
  924.    
  925.     /*
  926.      * Function: _fnCheckCC
  927.      * Purpose:  See if a conditional comment should be processed
  928.      * Returns:  int: 1-process, 0-don't process
  929.      * Inputs:   string:sCC - the conditional comment
  930.      *
  931.      * Notes:
  932.      * The browser conditions are:
  933.      *  [if {!} {browser}]
  934.      *  [if {!} {browser} {version}]
  935.      *  [if {!} {condition} {browser} {version}]
  936.      */
  937.     private function _fnCheckCC ( $sCC )
  938.     {
  939.         // Strip brackets from the CC
  940.         $sCC = str_replace( '[', '', $sCC );
  941.         $sCC = str_replace( ']', '', $sCC );
  942.        
  943.         $aCC = explode ( " ", $sCC );
  944.        
  945.         $bNegate = false;
  946.         if ( isset($aCC[1]) && $aCC[1] == "!" )
  947.         {
  948.             $bNegate = true;
  949.            
  950.             // Remove the negation operator so all the other operators are in place
  951.             array_splice ( $aCC, 1, 1 );
  952.         }
  953.        
  954.         //
  955.         // Do the logic checking
  956.         //
  957.         $bInclude = false;
  958.        
  959.         // If the CC is an integer, then we drop the minor version number from the
  960.         // users browser. This means that if the user is using v5.5, and the
  961.         // statement is for v5, then it matches. To stop this a CC with v5.0 would
  962.         // have to be used
  963.         $sLocalUserVersion = $this->sUserVersion;
  964.         if ( count($aCC) == 3 && !strpos( $aCC[2], "." ) ) /* if {browser} {version} */
  965.         {
  966.             $sLocalUserVersion = intval( $sLocalUserVersion );
  967.         }
  968.         else if ( count($aCC) == 4 && !strpos( $aCC[3], "." ) ) /* if {condition} {browser} {version} */
  969.         {
  970.             $sLocalUserVersion = intval( $sLocalUserVersion );
  971.         }
  972.        
  973.        
  974.         // Just the browser
  975.         if ( count( $aCC ) == 2 )
  976.         {
  977.             if ( $this->sUserBrowser == $aCC[1] ||
  978.                    $this->sUserGroup == $aCC[1] )
  979.             {
  980.                 $bInclude = true;
  981.             }
  982.         }
  983.         // Browser and version
  984.         else if ( count( $aCC ) == 3 )
  985.         {
  986.             if ( $this->sUserBrowser == $aCC[1] && (float)$sLocalUserVersion == (float)$aCC[2] )
  987.             {
  988.                 $bInclude = true;
  989.             }
  990.         }
  991.         // Borwser and version with operator
  992.         else if ( count( $aCC ) == 4 )
  993.         {
  994.             if ( $aCC[1] == "lt" )
  995.             {
  996.                 if ( $this->sUserBrowser == $aCC[2] && (float)$sLocalUserVersion < (float)$aCC[3] )
  997.                 {
  998.                     $bInclude = true;
  999.                 }
  1000.             }
  1001.             else if ( $aCC[1] == "lte" )
  1002.             {
  1003.                 if ( $this->sUserBrowser == $aCC[2] && (float)$sLocalUserVersion <= (float)$aCC[3] )
  1004.                 {
  1005.                     $bInclude = true;
  1006.                 }
  1007.             }
  1008.             else if ( $aCC[1] == "eq" )
  1009.             {
  1010.                 if ( $this->sUserBrowser == $aCC[2] && (float)$sLocalUserVersion == (float)$aCC[3] )
  1011.                 {
  1012.                     $bInclude = true;
  1013.                 }
  1014.             }
  1015.             else if ( $aCC[1] == "gte" )
  1016.             {
  1017.                 if ( $this->sUserBrowser == $aCC[2] && (float)$sLocalUserVersion >= (float)$aCC[3] )
  1018.                 {
  1019.                     $bInclude = true;
  1020.                 }
  1021.             }
  1022.             else if ( $aCC[1] == "gt" )
  1023.             {
  1024.                 if ( $this->sUserBrowser == $aCC[2] && (float)$sLocalUserVersion > (float)$aCC[3] )
  1025.                 {
  1026.                     $bInclude = true;
  1027.                 }
  1028.             }
  1029.         }
  1030.        
  1031.         // Perform negation if required
  1032.         if ( $bNegate )
  1033.         {
  1034.             if ( $bInclude )
  1035.             {
  1036.                 $bInclude = false;
  1037.             }
  1038.             else
  1039.             {
  1040.                 $bInclude = true;
  1041.             }
  1042.         }
  1043.        
  1044.         // Return the required type
  1045.         if ( $bInclude )
  1046.         {
  1047.             return 1;
  1048.         }
  1049.         else
  1050.         {
  1051.             return 0;
  1052.         }
  1053.     }
  1054. };
  1055.  
  1056.  
  1057.  
  1058.  
  1059. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1060.  * Processing - actually run Conditional-CSS
  1061.  */
  1062. $oCss = new ccss();
  1063. $oCss->fnComplete();
  1064.  
  1065. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement