Source: flipcss.phps - download
<?php
/* 
 * 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 3 of the License, or
 * (at your option) any later version.
 * 
 * flipcss.php 0.9.2
 * by Daif Alazmi (http://daif.net)
 * daif@daif.net
 * 
 * Link:
 *  http://daif.net/flipcss/flipcss.phps
 * 
 * Description:
 *  This Tool flip CSS rules direction from LTR to RTL or vice versa .
 *  tool support these CSS rules: float, text-align, padding, margin
 *  and border-radius .
 * 
 * Syntax:
 *  right to left
 *  $flip = new FlipCSS();
 *  $rtl_css = $flip->parseCSS($css_data, 'RTL', array('.pull-right', '.pull-left'));
 *  left to right
 *  $flip = new FlipCSS();
 *  $ltr_css = $flip->parseCSS($css_data, 'LTR', array('.pull-right', '.pull-left'));
 * 
 * Changelog
 * 0.1    first release
 * 0.2    rewrite padding and margin
 * 0.3    support border-radius
 * 0.4    added GPL License
 * 0.5    support border
 * 0.6    fix issue with rewrite padding,margin,border Regex
 * 0.7    added the $escaped parameter
 * 0.8    some code improvement
 * 0.9    fix parsing issue with two braces like @media , @-*
 * 0.9.1  ignore escape array it is count zero. 
 * 0.9.2  fix parsing left and right if not start with spaces.
*/



class FlipCSS{
    /**
     * version number
     *
     * @var string
     */
    public $version = '0.9.2';

    /**
     * CSS content
     *
     * @var string
     */
    public $css_data;

    /**
     * flipped CSS content
     *
     * @var string
     */
    public $css_flipped;
    /**
     * CSS ignored class name
     *
     * @var array
     */
    public $escaped = array('.pull-right','.pull-left','.text-left','.text-right','.left','.right');

    /**
     * Parse the CSS data
     *
     * @param   string
     * @param   string
     * @param   array
     * @return  string
     */
    public function parseCSS($css_data, $dir='RTL', $escaped=array()) {
        $this->css_data     =   $css_data;
        //set Generated by message
        $this->css_flipped  = "/* Generated by flipcss.php ".$this->version.
                                " (http://flipcss.com/) */\nbody{\n  direction:$dir;\n}\n\n";
        // remove comments
        $this->css_data     = preg_replace('/\*\//',"*/\n" ,$this->css_data);
        $this->css_data     = preg_replace('/\/\*(.*)?\*\//Usi','' ,$this->css_data);
        //remove @charset
        $this->css_data     = preg_replace('/@charset .+;/Ui',"", $this->css_data);
        // try to unminify minified css
        $this->css_data     = preg_replace('/{/'," {\n", $this->css_data);
        $this->css_data     = preg_replace('/}/',"\n}\n", $this->css_data);
        $this->css_data     = preg_replace('/;/',";\n", $this->css_data);
        $this->css_data     = preg_replace('/,/',",\n", $this->css_data);
        // rewrite padding,margin,border
        $this->css_data     =   preg_replace('/(\h*)(padding|margin|border)\h*:\h*(\d+.*)\h+(\d+.*)\h+(\d+.*)\h+(\d+.*)\h*;/Ui', 
                                    "\\1\\2-right:\\4;\n\\1\\2-left:\\6;\n" ,$this->css_data);
        // rewrite border-radius 
        $this->css_data     = preg_replace('/(\h*|)border-radius:(.+)\h+(.+)\h+(.+)\h+(.+)\h*;/Ui',"\\1border-top-left-radius:\\2;\\1border-top-".
                    "right-radius:\\3;\\1border-bottom-right-radius:\\4;\\1border-bottom-left-radius:\\5;", $this->css_data);
        // start parsing css file
        // find all class name
        preg_match_all('/((@(media).+{.+{.+}\s+})|(((?!@(m|-)).)+{.+}))/Uis', $this->css_data, $css_arr);
        // prepare regex
        $regex = trim(trim(implode('|', array_map('preg_quote', $escaped))), '|');
        //foreach the result array 
        foreach($css_arr[0] as $css_key=>$css_val) {
            if(preg_match('/@(m|-)(.+){(.+})\s+}/Uis', $css_arr[0][$css_key], $media_arr)) {
                $css_prefix = "@".$media_arr[1].$media_arr[2]." {\n";
                $css_inner  = '';
                preg_match_all('/(.+){(.+)}/Uis', $media_arr[3], $css_rules);
                foreach($css_rules[0] as $sub_key=>$sub_val) {
                    //ignore escaped classes
                    if(!$regex || ($regex && !preg_match('/('.$regex.')/i', $css_rules[1][$sub_key]))) {
                        if($rules = $this->parseCSSRules($css_rules[2][$sub_key])) {
                            $css_inner .= $css_rules[1][$sub_key]." {\n";
                            $css_inner .= "    ".str_replace(";\n", ";\n    ",trim($rules))."\n";
                            $css_inner .= "  }\n";
                        }
                    }
                }
                $css_suffix = "}\n";
            } else {
                preg_match_all('/(.+){(.+)}/Uis', $css_arr[0][$css_key], $css_rules);
                $css_prefix = '';
                $css_inner  = '';
                foreach($css_rules[0] as $sub_key=>$sub_val) {
                    //ignore escaped classes
                    if(!$regex || ($regex && !preg_match('/('.$regex.')/i', $css_rules[1][$sub_key]))) {
                        if($rules = $this->parseCSSRules($css_rules[2][$sub_key])) {
                            $css_inner .= $css_rules[1][$sub_key]." {\n";
                            $css_inner .= "  ".str_replace(";\n", ";\n  ",trim($rules))."\n";
                            $css_inner .= "}\n";
                        }
                    }
                }
                $css_suffix = "";
            }
            if($css_inner) {
                $this->css_flipped .= $css_prefix . $css_inner . $css_suffix;
                $this->css_flipped  = preg_replace('/({|})\n\n/Ui',"\\1\n", $this->css_flipped);
                $this->css_flipped  = preg_replace('/\s\s{/Ui'," {", $this->css_flipped);
                $this->css_flipped  = preg_replace('/(\v)\v+/',"\\1", $this->css_flipped);
            }
        }
        return ($this->css_flipped);
    }

    /**
     * Parse and flip the CSS data
     *
     * @param   string
     * @return  string
     */
    public function parseCSSRules($rules) {
        $return         = '';
        $rules_arr      = explode(";", $rules);
        foreach($rules_arr as $rule) {
            //ignore rules that doesn't need flipping
            if(preg_match('/(left|right)/i', $rule)) {
                //flip float
                if(preg_match('/float\h*:\h*(.+)/i', $rule, $rule_arr)) {
                    $rule    = 'float: '.((trim($rule_arr[1])=='left')?'right':'left');
                    $return .= trim($rule).";\n";
                
                //flip text-align
                } elseif(preg_match('/text-align\h*:\h*(.+)/i', $rule, $rule_arr)) {
                    $rule    = 'text-align: '.((trim($rule_arr[1])=='left')?'right':'left');
                    $return .= trim($rule).";\n";
                
                //flip padding, margin, border
                } elseif(preg_match('/(\*|)(margin|padding|border)-(left|right)\h*:\h*(.+)/i', $rule, $rule_arr)) {
                    $dir = ((trim($rule_arr[3])=='left')?'right':'left');
                    //reset direction rule
                    if((trim($rule_arr[3]) == 'left' && !preg_match('/'.trim($rule_arr[2]).'\-right/i', $rules)) || (trim($rule_arr[2]) == 'right' && !preg_match('/'.trim($rule_arr[2]).'\-left/i', $rules))) {
                        $rule = trim($rule_arr[1]).trim($rule_arr[2]).'-'.$rule_arr[3].": 0;\n";
                    } else {
                        $rule = '';
                    }
                    $rule   .= trim($rule_arr[1]).trim($rule_arr[2]).'-'.$dir.': '.$rule_arr[4];
                    $return .= trim($rule).";\n";
                
                //flip border-radius
                } elseif(preg_match('/border-(top|bottom)-(left|right)-radius\h*:\h*(.+)/i', $rule, $rule_arr)) {
                    $dir = ((trim($rule_arr[2])=='left')?'right':'left');
                    //reset direction rule
                    if((trim($rule_arr[2]) == 'left' && !preg_match('/'.trim($rule_arr[1]).'\-right/i', $rules)) || (trim($rule_arr[2]) == 'right' && !preg_match('/'.trim($rule_arr[1]).'\-left/i', $rules))) {
                        $rule = 'border-'.$rule_arr[1].'-'.$rule_arr[2].'-radius: 0;'."\n";
                    } else {
                        $rule = '';
                    }
                    //write new direction rule
                    $rule   .= 'border-'.$rule_arr[1].'-'.$dir.'-radius: '.$rule_arr[3];
                    $return .= trim($rule).";\n";
                
                //flip left, right
                } elseif(preg_match('/\h*(left|right)\h*:\h*(.+)/i', $rule, $rule_arr)) {
                    $dir = ((trim($rule_arr[1])=='left')?'right':'left');
                    //reset LTR rule
                    if((trim($rule_arr[1]) == 'left' && !preg_match('/\h+right\h*:/i', $rules)) || (trim($rule_arr[1]) == 'right' && !preg_match('/\h+left\h*:/i', $rules))) {
                        $rule = trim($rule_arr[1]).": auto;\n";
                    } else {
                        $rule = '';
                    }
                    $rule   .= $dir.': '.$rule_arr[2];
                    $return .= trim($rule).";\n";
                }
            }
        }
        return($return);
    }
}   
?>