~ overflow ~

Coding

Itaú shopline class

by z3n on Sep.03, 2010, under Coding

Problema:

A integração PHP proposta pelo Itaú é desastrosa, uma classe compilada em Java que requer um módulo beta descontinuado em PHP.

Solução:

Utilizando engenharia reversa descompilei a classe:

package Itau;

public class Itaucripto
{

    public Itaucripto()
    {
        CHAVE_ITAU = "SEGUNDA12345ITAU";
        TAM_COD_EMP = 26;
        TAM_CHAVE = 16;
        numbers = "0123456789";
        sbox = new int[256];
        key = new int[256];
        numPed = "";
        tipPag = "";
        codEmp = "";
    }

    private String Algoritmo(String s, String s1)
    {
        int k = 0;
        int l = 0;
        String s2 = "";
        Inicializa(s1);
        for(int j = 1; j <= s.length(); j++)
        {
            k = (k + 1) % 256;
            l = (l + sbox[k]) % 256;
            int i = sbox[k];
            sbox[k] = sbox[l];
            sbox[l] = i;
            int i1 = sbox[(sbox[k] + sbox[l]) % 256];
            int j1 = s.charAt(j - 1) ^ i1;
            s2 = s2 + (char)j1;
        }

        return s2;
    }

    private String PreencheBranco(String s, int i)
    {
        String s1;
        for(s1 = s.toString(); s1.length() < i; s1 = s1 + " ");
        return s1.substring(0, i);
    }

    private String PreencheZero(String s, int i)
    {
        String s1;
        for(s1 = s.toString(); s1.length() < i; s1 = "0" + s1);
        return s1.substring(0, i);
    }

    private void Inicializa(String s)
    {
        int i1 = s.length();
        for(int j = 0; j <= 255; j++)
        {
            key[j] = s.charAt(j % i1);
            sbox[j] = j;
        }

        int l = 0;
        for(int k = 0; k <= 255; k++)
        {
            l = (l + sbox[k] + key[k]) % 256;
            int i = sbox[k];
            sbox[k] = sbox[l];
            sbox[l] = i;
        }

    }

    private boolean isNumeric(String s)
    {
        if(s.length() > 1)
        {
            boolean flag = true;
            for(int i = 0; i < s.length(); i++)
            {
                flag = isNumeric(s.substring(i, i + 1));
                if(!flag)
                    return flag;
            }

            return flag;
        }
        return numbers.indexOf(s) >= 0;
    }

    private String Converte(String s)
    {
        char c2 = (char)(int)(26D * Math.random() + 65D);
        String s1 = "" + c2;
        for(int i = 0; i < s.length(); i++)
        {
            char c1 = s.charAt(i);
            char c = c1;
            s1 = s1 + Integer.toString(c);
            char c3 = (char)(int)(26D * Math.random() + 65D);
            s1 = s1 + c3;
        }

        return s1;
    }

    private String Desconverte(String s)
    {
        String s1 = "";
        for(int i = 0; i < s.length(); i++)
        {
            String s2 = "";
            for(char c = s.charAt(i); Character.isDigit(c); c = s.charAt(i))
            {
                s2 = s2 + s.charAt(i);
                i++;
            }

            if(s2.compareTo("") != 0)
            {
                int j = Integer.parseInt(s2);
                s1 = s1 + (char)j;
            }
        }

        return s1;
    }

    public String geraDados(String s, String s1, String s2, String s3, String s4, String s5, String s6,
            String s7, String s8, String s9, String s10, String s11, String s12, String s13,
            String s14, String s15, String s16, String s17)
    {
        s = s.toUpperCase();
        s4 = s4.toUpperCase();
        if(s.length() != TAM_COD_EMP)
            return "Erro: tamanho do codigo da empresa diferente de 26 posi\347\365es.";
        if(s4.length() != TAM_CHAVE)
            return "Erro: tamanho da chave da chave diferente de 16 posi\347\365es.";
        if(s1.length() < 1 || s1.length() > 8)
            return "Erro: n\372mero do pedido inv\341lido.";
        if(isNumeric(s1))
            s1 = PreencheZero(s1, 8);
        else
            return "Erro: numero do pedido n\343o \351 num\351rico.";
        if(s2.length() < 1 || s2.length() > 11)
            return "Erro: valor da compra inv\341lido.";
        int i = s2.indexOf(',');
        if(i != -1)
        {
            String s20 = s2.substring(i + 1);
            if(!isNumeric(s20))
                return "Erro: valor decimal n\343o \351 num\351rico.";
            if(s20.length() != 2)
                return "Erro: valor decimal da compra deve possuir 2 posi\347\365es ap\363s a virgula.";
            s2 = s2.substring(0, s2.length() - 3) + s20;
        } else
        {
            if(!isNumeric(s2))
                return "Erro: valor da compra n\343o \351 num\351rico.";
            if(s2.length() > 8)
                return "Erro: valor da compra deve possuir no m\341ximo 8 posi\347\365es antes da virgula.";
            s2 = s2 + "00";
        }
        s2 = PreencheZero(s2, 10);
        s6 = s6.trim();
        if(s6.compareTo("02") != 0 && s6.compareTo("01") != 0 && s6.compareTo("") != 0)
            return "Erro: c\363digo de inscri\347\343o inv\341lido.";
        if(s7.compareTo("") != 0 && !isNumeric(s7) && s7.length() > 14)
            return "Erro: n\372mero de inscri\347\343o inv\341lido.";
        if(s10.compareTo("") != 0 && (!isNumeric(s10) || s10.length() != 8))
            return "Erro: cep inv\341lido.";
        if(s13.compareTo("") != 0 && (!isNumeric(s13) || s13.length() != 8))
            return "Erro: data de vencimento inv\341lida.";
        if(s15.length() > 60)
            return "Erro: observa\347\343o adicional 1 inv\341lida.";
        if(s16.length() > 60)
            return "Erro: observa\347\343o adicional 2 inv\341lida.";
        if(s17.length() > 60)
        {
            return "Erro: observa\347\343o adicional 3 inv\341lida.";
        } else
        {
            s3 = PreencheBranco(s3, 40);
            s5 = PreencheBranco(s5, 30);
            s6 = PreencheBranco(s6, 2);
            s7 = PreencheBranco(s7, 14);
            s8 = PreencheBranco(s8, 40);
            s9 = PreencheBranco(s9, 15);
            s10 = PreencheBranco(s10, 8);
            s11 = PreencheBranco(s11, 15);
            s12 = PreencheBranco(s12, 2);
            s13 = PreencheBranco(s13, 8);
            s14 = PreencheBranco(s14, 60);
            s15 = PreencheBranco(s15, 60);
            s16 = PreencheBranco(s16, 60);
            s17 = PreencheBranco(s17, 60);
            String s18 = Algoritmo(s1 + s2 + s3 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + s16 + s17, s4);
            String s19 = Algoritmo(s + s18, CHAVE_ITAU);
            return Converte(s19);
        }
    }

    public String geraCripto(String s, String s1, String s2)
    {
        if(s.length() != TAM_COD_EMP)
            return "Erro: tamanho do codigo da empresa diferente de 26 posi\347\365es.";
        if(s2.length() != TAM_CHAVE)
            return "Erro: tamanho da chave da chave diferente de 16 posi\347\365es.";
        s1 = s1.trim();
        if(s1.compareTo("") == 0)
        {
            return "Erro: c\363digo do sacado inv\341lido.";
        } else
        {
            String s3 = Algoritmo(s1, s2);
            String s4 = Algoritmo(s + s3, CHAVE_ITAU);
            return Converte(s4);
        }
    }

    public String geraConsulta(String s, String s1, String s2, String s3)
    {
        if(s.length() != TAM_COD_EMP)
            return "Erro: tamanho do codigo da empresa diferente de 26 posi\347\365es.";
        if(s3.length() != TAM_CHAVE)
            return "Erro: tamanho da chave da chave diferente de 16 posi\347\365es.";
        if(s1.length() < 1 || s1.length() > 8)
            return "Erro: n\372mero do pedido inv\341lido.";
        if(isNumeric(s1))
            s1 = PreencheZero(s1, 8);
        else
            return "Erro: numero do pedido n\343o \351 num\351rico.";
        if(s2.compareTo("0") != 0 && s2.compareTo("1") != 0)
        {
            return "Erro: formato inv\341lido.";
        } else
        {
            String s4 = Algoritmo(s1 + s2, s3);
            String s5 = Algoritmo(s + s4, CHAVE_ITAU);
            return Converte(s5);
        }
    }

    public String decripto(String s, String s1)
    {
        s = Desconverte(s);
        String s2 = Algoritmo(s, s1);
        codEmp = s2.substring(0, 26);
        numPed = s2.substring(26, 34);
        tipPag = s2.substring(34, 36);
        return s2;
    }

    public String retornaCodEmp()
    {
        return codEmp;
    }

    public String retornaPedido()
    {
        return numPed;
    }

    public String retornaTipPag()
    {
        return tipPag;
    }

    public String geraDadosGenerico(String s, String s1, String s2)
    {
        s = s.toUpperCase();
        s2 = s2.toUpperCase();
        if(s.length() != TAM_COD_EMP)
            return "Erro: tamanho do codigo da empresa diferente de 26 posi\347\365es.";
        if(s2.length() != TAM_CHAVE)
            return "Erro: tamanho da chave da chave diferente de 16 posi\347\365es.";
        if(s1.length() < 1)
        {
            return "Erro: sem dados.";
        } else
        {
            String s3 = Algoritmo(s1, s2);
            String s4 = Algoritmo(s + s3, CHAVE_ITAU);
            return Converte(s4);
        }
    }

    private int sbox[];
    private int key[];
    private String codEmp;
    private String numPed;
    private String tipPag;
    private String CHAVE_ITAU;
    private int TAM_COD_EMP;
    private int TAM_CHAVE;
    private String dados;
    public String numbers;
}

Nada satisfatório, mas é melhor do que utilizar o módulo java beta ou a integração windows emulada no linux.

Também achei um port em PHP, não é uma maravilha, mas dá pro gasto por enquanto.

Leave a Comment :, , , , , more...

preg (regular expression) to get emails in php

by z3n on Aug.28, 2010, under Coding

Problem:

A regular experssion pattern for getting emails on a random string.

Solution:

preg_match_all(
	"/[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i",
	$string,
	$matches,
	PREG_PATTERN_ORDER
);
Leave a Comment :, , , more...

.htaccess to redirect root to folder

by z3n on Aug.04, 2010, under Coding, Tips & Hints

Problem:

How to do a 302/permanent SEO compliant redirect from a root folder to somewhere else?

Solution:

RedirectMatch permanent ^/$ http://mydomain.com/php/index.php

Source:

digitalpoint

Leave a Comment :, , , more...

BBCode php parser class

by z3n on Jul.10, 2010, under Coding, Tips & Hints

This class is based on jquery’s markitup plugin function, i did some code compressions and added youtube handler to it. If you need base_defines function, just search the site.

class BBCodeParser {
	private $text;

	public function __construct() {
		base_defines(array(
			"EMOTICONS_DIR" => "/img/emoticons/"
		));
	}

	public function escape($s) {
		$this->text = strip_tags($this->text);
		$code = $s[1];
		$code = htmlspecialchars($code);
		$code = str_replace("[", "&#91;", $code);
		$code = str_replace("]", "&#93;", $code);
		return '<pre><code>'.$code.'</code></pre>';
	}	

	public function removeBr($s) {
		return str_replace("<br />", "", $s[0]);
	}

	public function parse($text) {
		$this->text = trim($text);
		$this->text = preg_replace(array(
				'/\[b\](.*?)\[\/b\]/ms',
				'/\[i\](.*?)\[\/i\]/ms',
				'/\[u\](.*?)\[\/u\]/ms',
				'/\[img\](.*?)\[\/img\]/ms',
				'/\[email\](.*?)\[\/email\]/ms',
				'/\[url\="?(.*?)"?\](.*?)\[\/url\]/ms',
				'/\[size\="?(.*?)"?\](.*?)\[\/size\]/ms',
				'/\[youtube\](.*?)\[\/youtube\]/ms',
				'/\[color\="?(.*?)"?\](.*?)\[\/color\]/ms',
				'/\[quote](.*?)\[\/quote\]/ms',
				'/\[list\=(.*?)\](.*?)\[\/list\]/ms',
				'/\[list\](.*?)\[\/list\]/ms',
				'/\[\*\]\s?(.*?)\n/ms'
			),array(
				'<strong>\1</strong>',
				'<em>\1</em>',
				'<u>\1</u>',
				'<img src="\1" alt="\1" />',
				'<a href="mailto:\1">\1</a>',
				'<a href="\1">\2</a>',
				'<span style="font-size:\1%">\2</span>',
				'<object width="450" height="350"><param name="movie" value="\1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="\1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="450" height="350"></embed></object>',
				'<span style="color:\1">\2</span>',
				'<blockquote>\1</blockquote>',
				'<ol start="\1">\2</ol>',
				'<ul>\1</ul>',
				'<li>\1</li>'
			),
			str_replace(array(
					':)',
					':D',
					':o',
					':p',
					':P',
					':(',
					';)'
				),array(
					'<img alt=":)" src="'.EMOTICONS_DIR.'emoticon-happy.png" />',
					'<img alt=":D" src="'.EMOTICONS_DIR.'emoticon-smile.png" />',
					'<img alt=":o" src="'.EMOTICONS_DIR.'emoticon-surprised.png" />',
					'<img alt=":p" src="'.EMOTICONS_DIR.'emoticon-tongue.png" />',
					'<img alt=":P" src="'.EMOTICONS_DIR.'emoticon-tongue.png" />',
					'<img alt=":(" src="'.EMOTICONS_DIR.'emoticon-unhappy.png" />',
					'<img alt=";)" src="'.EMOTICONS_DIR.'emoticon-wink.png" />'
				),
				preg_replace_callback(
					'/\[code\](.*?)\[\/code\]/ms',
					array(&$this, "escape"), // http://www.php.net/manual/en/function.preg-replace-callback.php#90849
					//"BBCodeParser::escape", // http://www.php.net/manual/en/function.preg-replace-callback.php#92548
					$this->text
				)
			)
		);

		// paragraphs
		$this->text = str_replace("\r", "", $this->text);
		$this->text = "<p>".preg_replace("/(\n){2,}/", "</p><p>", $this->text)."</p>";
		$this->text = nl2br($this->text);

		// clean some tags to remain strict
		// not very elegant, but it works. No time to do better ;) 

		$this->text = preg_replace_callback('/<pre>(.*?)<\/pre>/ms', array(&$this,"removeBr"), $this->text);
		$this->text = preg_replace('/<p><pre>(.*?)<\/pre><\/p>/ms', "<pre>\\1</pre>", $this->text);

		$this->text = preg_replace_callback('/<ul>(.*?)<\/ul>/ms', array(&$this,"removeBr"), $this->text);
		$this->text = preg_replace('/<p><ul>(.*?)<\/ul><\/p>/ms', "<ul>\\1</ul>", $this->text);

		return $this->text;
	}
}
Leave a Comment :, , , more...

MarkItUp set em português (pt-br)

by z3n on Jul.10, 2010, under Coding, Tips & Hints

Variáveis de markitup em português com youtube

markitup_bbcode = {
  nameSpace:          "bbcode", // Useful to prevent multi-instances CSS conflict
  previewParserPath:  "~/sets/bbcode/preview.php",
  markupSet: [
      {name:'Negrito', key:'B', openWith:'[b]', closeWith:'[/b]'},
      {name:'Italico', key:'I', openWith:'[i]', closeWith:'[/i]'},
      {name:'Sublinhado', key:'U', openWith:'[u]', closeWith:'[/u]'},
      {separator:'---------------' },
      {name:'Imagem', key:'P', replaceWith:'[img][![Url]!][/img]'},
      {name:'YouTube', key:'Y', openWith:'[youtube]', closeWith:'[/youtube]', placeHolder:'[![Url do YouTube]!]'},
      {name:'Link', key:'L', openWith:'[url=[![Url]!]]', closeWith:'[/url]', placeHolder:'Coloque o texto do link aqui...'},
      {separator:'---------------' },
      {name:'Cores', openWith:'[color=[![Cor]!]]', closeWith:'[/color]', dropMenu: [
          {name:'Amarelo', openWith:'[color=yellow]', closeWith:'[/color]', className:"col1-1" },
          {name:'Laranja', openWith:'[color=orange]', closeWith:'[/color]', className:"col1-2" },
          {name:'Vermelho', openWith:'[color=red]', closeWith:'[/color]', className:"col1-3" },
          {name:'Azul', openWith:'[color=blue]', closeWith:'[/color]', className:"col2-1" },
          {name:'Roxo', openWith:'[color=purple]', closeWith:'[/color]', className:"col2-2" },
          {name:'Verde', openWith:'[color=green]', closeWith:'[/color]', className:"col2-3" },
          {name:'Branco', openWith:'[color=white]', closeWith:'[/color]', className:"col3-1" },
          {name:'Cinza', openWith:'[color=gray]', closeWith:'[/color]', className:"col3-2" },
          {name:'Preto', openWith:'[color=black]', closeWith:'[/color]', className:"col3-3" }
      ]},
      {name:'Tamanho', key:'S', openWith:'[size=[![Tamanho do texto]!]]', closeWith:'[/size]', dropMenu :[
          {name:'Grande', openWith:'[size=200]', closeWith:'[/size]' },
          {name:'Normal', openWith:'[size=100]', closeWith:'[/size]' },
          {name:'Pequeno', openWith:'[size=50]', closeWith:'[/size]' }
      ]},
      {separator:'---------------' },
      {name:'Quotes', openWith:'[quote]', closeWith:'[/quote]'},
      {separator:'---------------' },
      {name:'Limpar', className:"clean", replaceWith:function(h) { return h.selection.replace(/\[(.*?)\]/g, "") } }
   ]
};
Leave a Comment :, , , more...

JQuery validator method for twitter

by z3n on Jul.07, 2010, under Coding, Tips & Hints

Problem:

How to validate twitter @your_crap_name using jQuery’s validator plugin?

Solution:

jQuery.validator.addMethod("twitter", function(twitter, element) {
	return this.optional(element) || twitter.match(/^@+\b[A-Z0-9._%-]+\b/i);
}, "Twitter inválido");
Leave a Comment :, , , more...

JSLint php class

by z3n on Jul.07, 2010, under Coding, Tips & Hints

Problem:

How to lint check a javascript using php?

Solution:

// (c) z3n - R1V1@100707 - www.overflow.biz - rodrigo.orph@gmail.com
// Based on the original by Matthias Miller (http://www.JavaScriptLint.com/)

class JSLEngine {
	private $_binarypath;							// jlint exec
	private $_confpath;								// config path
	private $fn;											// temp filename (not used outside class)
	private $r;												// jlint output
	private $has_errors=0;						// error flag

	public function __construct($binarypath="", $confpath="") {

		// default paths
		base_defines(array(
			"jslint_binary_path" => _fn_fix(dirname(dirname(dirname(__FILE__)))."/3rd/jsl-0.3.0/jsl.exe"),
			"jslint_conf_path" => _fn_fix(dirname(dirname(dirname(__FILE__)))."/3rd/jsl-0.3.0/jsl.default.conf")
		));

		// startup
	  $this->_binarypath = $binarypath == "" ? jslint_binary_path : $binarypath;
	  $this->_confpath = $confpath == "" ? jslint_conf_path : $confpath;
	}

	public function __destruct() {
		if ($this->fn != null && file_exists($this->fn))
			unlink($this->fn);
	}

	/* returns error on failure; returns true on success */
	public function Lint($code) {
	  if (!$this->_launchLintBinary($code, $output))
	      die('The JavaScript Lint online service is currently unavailable.');

	  // store lint
	  $this->r=$output;
	  $output=explode("\n",$output); // break lines
	  $x=$output[count($output)-2]; // X error(s), X warning(s) (total lines -2)
	  $x=trim(substr($x,0,strpos($x," ")));
	  if ($x > 0) { // has errors
	  	$this->has_errors=1;
	  	return false;
	  } else { // clean
	  	$this->has_errors=0;
	  	return true;
	  }
	}

	/* assumes path and that SERVER_SOFTWARE env is set */
	private function _launchLintBinary($input, &$output) {
    $descriptorspec = array(
        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
        1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
        2 => array("pipe", "w")
    );

    $this->fn=_fn_fix(dirname(__FILE__).'/tmp.js');

    file_put_contents($this->fn,$input);
    /* launch process */
    $path = PHP_OS == "WINNT" ? $this->_binarypath : escapeshellcmd($this->_binarypath);
    $path.= ' --nologo --conf '.escapeshellarg($this->_confpath).' --process '.escapeshellarg($this->fn);

    $process = proc_open($path, $descriptorspec, $pipes);
    if (!is_resource($process))
        return false;

    $output = '';
    while (!feof($pipes[1]))
       $output .= fgets($pipes[1], 1024);
    fclose($pipes[1]);
    fclose($pipes[2]);

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);
    return true;
	}

	public function output() {
		return $this->r;
	}
}

Helper functions:


function _fn_fix($fn,$force="") { // v1.02
	if (strpos($fn,"://") === false) {
		if ((PHP_OS == "WINNT" && $force == "") || $force == "WINNT")
			$fn=str_replace("/","\\",$fn);
		else
			$fn=str_replace("\\","/",$fn);
	}
	if (strpos($fn,":/") !== false && strpos($fn,"://") === false)
		$fn=substr($fn,2);

	return $fn;
}

function base_defines($x) { // define default
	foreach ($x as $k => $v) {
		if (!defined($k)) {
			define($k,$v);
		}
	}
}

Usage:

$lint=new JSLEngine();
if (!$lint->Lint($js)) {
    echo "bad js code! full output:\n";
    echo $lint->output();
}

Required:

jslint binaries from http://www.JavaScriptLint.com/

Make sure you set the default path on the __construct, so you don’t need to keep setting it on every call.

Leave a Comment :, , , , , more...

jQuery validator validate a single field

by z3n on Jul.06, 2010, under Coding, Tips & Hints

Problem:

How to programatically validade a single non keyup field with jquery validator?

Solution:

$("input[name=YOUR_FIELD_NAME]").valid()
Leave a Comment :, , , , more...

How to abort ajax requests gracefully

by z3n on Jun.28, 2010, under Coding, Tips & Hints

Problem:

Ajax is great, everyone knows, but sometimes for network issues, server slowdowns or simply users issues request fails or keep loading for a long time. How to abort a request or all of them without needing to reload the whole page?

Solution:

First you need to throw all your ajax requests into a array, that way you can use it as api, so you can abort any “slow” requests, in my case i have a complex admin interface which sometimes bugs or get swamped with lots of requests at same time, usually due user related issues, so i added this “cancel” button which clears up all pending ajax requests, making the system more realiable. Before developing it i did a test on how it works, here’s the source:

<?php

// (c) z3n - R1V1@100628 - www.overflow.biz - rodrigo.orph@gmail.com

if (isset($_REQUEST['q'])) {
	header('Content-Type: application/json; charset=utf-8'); // mandatory for jquery compatibility
	if (!isset($_REQUEST['a']))
		sleep(20);
	echo json_encode(array("r" => 1));
	die;
} else {

?>

<html>
	<head>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>
		<script type="text/javascript">
			var _ajax=[];

			function do_dbg(msg) {
				$("#dbg").prepend(msg+"<BR>");
			}

			function do_ajax() {
				do_dbg("do ajax");
				_ajax[_ajax.length] = $.ajax({data:"q=something",success:function(r,s) {
					do_dbg("do ajax reply");
					return;
				}});
			}

			function do_ajax_fast() {
				do_dbg("do ajax_fast");
				_ajax[_ajax.length] = $.ajax({data:"q=something&a=other_thing",success:function(r,s) {
					do_dbg("do ajax fast reply");
					return;
				}});
			}

			function kill_ajax() {
				do_dbg("aborting all ajax");
				for (var i in _ajax)
					_ajax[i].abort();
			}

			$(document).ready(function(){
				$.ajaxSetup({
					url:"<?=$_SERVER['PHP_SELF']?>",
					global:true,
					type:"POST",
					dataType:'json',
					cache:false,
					async:true,
					timeout:12000000,
					scriptCharset:"UTF-8"
				});
			});
		</script>
	</head>
	<body>
		<input type="button" onClick="do_ajax();" value="do ajax">
		<input type="button" onClick="kill_ajax();" value="kill ajax">
		<input type="button" onClick="do_ajax_fast();" value="do ajax fast">

		<BR><BR>

		<span id="dbg"></span>
	</body>
</html>
<?php

}

?>

Have fun!

Leave a Comment :, , more...

CSS Packer Reloaded

by z3n on Jun.21, 2010, under Coding, Tips & Hints

Sometime ago i posted a simple css packer which basically wipes out the whitespaces,  new lines and so on. The javascript packer was also included. Although none of those were 100% my creations i’ve improved the way it works by adding a couple of things:

- Caching based on timestamp on files (aka automatic cache expiry on update)

- Packing multiple files into a single one (ex. if you have 100s of jquery extensions you don’t need to pack them individually, packing everything into a single file is faster and smaller)

- Flexible layout for packing IE specific files

Source:

function css_specifics($fn) {
	global $_GET;
	if (isset($_GET['q'])) {
		return str_replace(".css",".".trim(str_replace(array("..","/"),"",$_GET['q'])).".css",$fn);
	} else {
		return $fn;
	}
}

base_defines(array(
	"css_packed" => _is_sadm ? "packed-adm.css" : "packed.css",												// css worked file output
	"css_include_path" => "css/",																											// css base include path
	"css_cache_path" => "css/cache/",																									// css cache path
	"css_compression" => -1,																													// css compression method, -1 = disabled
	"css_copyright" => "/* (c) z3n - www.overflow.biz - rodrigo.orph@gmail.com */\n\n", 	// css copyright notice, will appear on packed verisons
	"css_debug" => 0,
	"css_gzip" => 1
));

$css="";
$_use_cache=0;
$css_packed=css_specifics(css_packed);

$l=(file_exists(css_cache_path.$css_packed)) ? filemtime(css_cache_path.$css_packed) : 0;

if (isset($css_includes) && (!empty($css_includes))) {
	if ($l > 0) { // check last mod first
		$_use_cache=1;
		if (css_debug)
			echo "collected includes: ".var_export($css_includes,true)."\n";
		foreach ($css_includes as $v) {
			$fn=_fn_fix($v{0} == "/" || strpos($v,":\\") !== false || $v{0} == "\\" ? $v : css_include_path.$v);
			if (css_debug)
				echo "checking lastmod for: ".$v."\n";
			if (foo((substr($v,0,5) == "http:") ?
					getlastmod($fn)
				:
					filemtime($fn)
			) > $l) {
				$_use_cache=0;
				break;
			}
		}
	}

	if (!$_use_cache) { // re/pack
		if (css_debug)
			echo "building new cache\n";
		// load all js into one
		foreach ($css_includes as $v)
			$css.=substr($v,0,5) == "http:" ?
					file_get_contents($v)."\n"
				:
					_fs($v{0} == "/" || strpos($v,":\\") !== false || $v{0} == "\\" ? $v : css_include_path.$v)."\n"
			;

		// @Packager.RemoveLine -> nothing

		if (css_debug)
			echo "replacing..\n";
		// perform basic replaces
		$css=str_replace(array(
				"##SITE_FULL_URI##"
			),array(
				site_full_uri
		),$css);

		// compress
		switch (css_compression) {
			case "0": // css tidy - http://csstidy.sourceforge.net/
				require_once("classes/csstidy/class.csstidy.php");

				$x=new csstidy();
				$x->set_cfg('preserve_css',true);
				$x->set_cfg('remove_last_;',true);
				$x->set_cfg('merge_selectors',1);
				$x->set_cfg('optimise_shorthands',1);
				$x->set_cfg('silent',true);
				$x->set_cfg('compress_colors',true);
				$x->set_cfg('sort_selectors',false);
				$x->set_cfg('sort_properties',false);
				$x->set_cfg('discard_invalid_properties',false);
				$x->set_cfg('timestamp',false);
				$x->load_template("highest_compression");

				$x->parse(strip_comments($css));
				$css=$x->print->plain();

				break;
			case "1": // minify - http://www.lateralcode.com/css-minifier/
				$css = preg_replace( '#\s+#', ' ', $css );
				$css = preg_replace( '#/\*.*?\*/#s', '', $css );
				$css = str_replace( '; ', ';', $css );
				$css = str_replace( ': ', ':', $css );
				$css = str_replace( ' {', '{', $css );
				$css = str_replace( '{ ', '{', $css );
				$css = str_replace( ', ', ',', $css );
				$css = str_replace( '} ', '}', $css );
				$css = str_replace( ';}', '}', $css );
				break;
			default: // no compression/invalid
				// nothing!
				break;
		}

		$css=css_copyright.$css; // add copyright notice

		if (css_debug)
			echo "writing cache..\n";

		_fw(css_cache_path.$css_packed,$css,"w"); // save cache
	} else { // use cache
		if (css_debug)
			echo "loading from cache\n";
		$css=_fs(css_cache_path.$css_packed);
	}

	if (css_debug)
		echo "output\n - - - \n".$css;

	_opt_headers(gmdate(_dt_lm,filemtime(css_cache_path.$css_packed))." GMT"); // check/send 304

	header('Content-Type: text/css');

	if (css_gzip) // compress
		ob_start("ob_gzhandler");

	print $css; // final output
}

die;

Usage:

Configure files to be added by:

$css_includes=array(
    "file1.css",
    "file2.css",
    "fileN.css",
    "http://www.remote.com/style.css"
);

Do the link by:

<link rel="stylesheet" href="/lib/css.php" type="text/css">
<!--[if IE]><link rel="stylesheet" href="/lib/css.php?q=ie" type="text/css"><![endif]-->

Assuming you have the source into /lib/css.php and, on this case, you have an exception for all IEs.

Notes:

css_include_path = source of css (uncompressed, commented)
css_cache_path = path to save the compressed css
css_compression = method of compression , -1 no compression , 0 = css tidy, 1 = minify
css_debug = enables step by step debug
css_gzip = forces php to output as gzip

Required:

CSS Tidy

You may also need some functions of my framework, i will post them when i compile a decent common file.

Leave a Comment :, , , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!