En esta ocasión comparto una librería o algoritmo que hice hace tiempo para comprimir documentos de gran tamaño.
El algoritmo jvm (Si, le puesto mis iníciales soy así de hortera) puede utilizarse con cualquier documento, pero es más eficiente con código HTML generado desde AS3, aunque es posible optimizarlo para otros sustituyendo en el array manualMath las cadenas especificas que se repiten con más frecuencia en los tipos de documentos que vayamos a comprimir, por ejemplo en el HTML generado por AS3 suelen ser las siguientes FONT, TEXTFORMAT, KERNING etc.
Si se comprimen textos muy pequeños el resultado será prácticamente el mismo e incluso mayor que el original, esto es normal ya que el resultado se aprecia cuanto más grande es el texto sobre todo si se trata de código HTML de AS3.
También comprimiría mas si utilizase más símbolos pero me encontré problemas con las codificaciones que no supe resolver y finalmente utilice unos pocos símbolos que supuestamente no dan problemas.
En el ejemplo podéis ver el código HTML de un documento de una sola página que ocupa unos 9.409 caracteres, el documento en si es poca cosa pero el HTML infla el tamaño considerablemente, pues bien el compresor realiza una compresión de 9.409 a 3.478 esto viene a ser una compresión superior al 50% del documento original. Gracias al compresor pude tratar y guardar en la base de datos gran cantidad de documentos de más de 30 páginas en HTML con más de 300.000 caracteres cada uno con un coste de procesamiento minimo.
Se me ocurre que también podría servir para encriptar texto, eso sí, sin clave pero se podría implementar.
Por ejemplo aquí abajo vemos el resultado de encriptar una frase.
Con diez cañones por banda viento en popa a toda vela no corre si no vuela un velero bergantín. (Bricobit)
þel,ý co,ü da,û en,ú er,ù ie,ø an,÷ no,ö on,õ or,ô po,ó to,òþÿCõ døz cañões pô b÷û viúò ú ópa a òû výa ö ürre si ö vuýa un výùo bùg÷tín. (Briübit)
Bueno no sé si llamarlo encriptar, cifrar o codificar pero da igual, el tema es que en un principio el algoritmo nunca establecerá la misma sustitución de caracteres, es decir no siempre cambiara por ejemplo una A por un *, si no que dependiendo de cada documento puede variar, eso sí un mismo documento siempre se codificara igual, pero con otro lo hará diferente por la lógica de que es un documento diferente y eso le otorga aleatoriedad en la sustitución de caracteres.
Saludos!!!.
Ejemplo: (Puedes introducir aquí otros textos o documento como HTML normal para probar el nivel de compresión, una vez comprimido también podrás editar el texto comprimido para introducir otros texto para descomprimir)
Clase as3 JVM.as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
package seguridad.algoritmos{ /** * Compresses and decompresses AS3HtmlText with the JVM algorithm in AS3. * @author: javier Vicente medina * @web: xavirobot.com - jvm.bricobit.com */ public class JVM { public static function compress( str:String,funStart:Function = null,funStop:Function = null):String { if(funStart != null){ funStart(); } var result:String; trace("Tamaño inicial -> " + str.length); //Buscamos 2 caracteres que no coincidna con ningun caracter de la cadena y los guardamos. var CONTROL_CHAR:Array = new Array(); var step:int = 0; var CHARS:Array = String("ÿþýüûúùø÷öõôóòñðïîíìëêéèçæåäãâáàßÞÝÜÛÚÙØ×ÖÕÔÓÒÑÐÏÎÍÌËÊÉÈÇÆÅÄÃÂÁÀ¿¾½¼»º¹¸•¶µ´³²±°¯®¬«ª©¨§¦¥¤£¢").split(""); var CHARS_LENGTH:int = CHARS.length; for (var u:int = 0; u<CHARS_LENGTH; u++) { CONTROL_CHAR[step] = CHARS[u]; if (str.indexOf(CONTROL_CHAR[step]) < 0) { step++; if (step == 2) { break; } } } //Comprobamos si existen comas en la cadena, si es asi la sustituimos por el primer caracter de control. if (str.indexOf(",") >= 0) { str = str.split(",").join(CONTROL_CHAR[0]); } /*Separamos la cadena y buscamos coincidencias para eliminarlas y guardamos posiciones para poder posteriormente reconstruir la cadena original.*/ var c:Array = str.split(" "); var s:int = c.length; for (var n:int = 0; n < s; n++) { c[n] = new Array(c[n]); } for (var i:int = 0; i < s - 1; i++) { if (c[i][1] == undefined && c[i][0].length > 3) { for (var j:int = i + 1; j < s; j++) { if (c[j][1] == undefined) { if (c[i][0] === c[j][0]) { c[j][0] = ""; c[j].push(i); } } } } } //Recuperamos todos los simbolos que no esten siendo utilizados en la cadena var SYMBOLUSE: Array = new Array(); for (var f:int=0; f<CHARS_LENGTH; f++) { var letter:String = CHARS[f]; if (letter!=CONTROL_CHAR[0] && letter!=CONTROL_CHAR[1]) { var symbolSustitute:String = CHARS[f]; if (str.indexOf(symbolSustitute) < 0) { SYMBOLUSE.push(symbolSustitute); } } } var su:int = SYMBOLUSE.length; str = c.join(" "); var NCNC:Array = new Array(); var ABC:Array = String("áéíóúàèìòùabcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789").split(""); var comb:String; var combMatches:int; var ManualMatch:Array = new Array('</FONT></P></TEXTFORMAT><TEXTFORMAT','KERNING="','"><B>','</B>'); var mml:int = ManualMatch.length; var FINALASOC:Array = new Array(); var correlative:int = 0; for (var mm:int=0; mm<mml; mm++) { comb = ManualMatch[mm]; combMatches = str.match(new RegExp(comb,"g")).length; if (combMatches >0) { str = str.split(comb).join(SYMBOLUSE[correlative]); FINALASOC.push(new Array(comb,SYMBOLUSE[correlative])); correlative++; } } var abcl:int = ABC.length; for (var q:int=0; q<abcl; q++) { for (var p:int=0; p<abcl; p++) { comb = ABC[q] + ABC[p]; combMatches = str.match(new RegExp(comb,"g")).length; if (combMatches >1) { NCNC.push({matches:combMatches, combL:comb}); } } } if (NCNC.length > 0 || FINALASOC.length > 0) { NCNC.sortOn("matches", Array.NUMERIC | Array.DESCENDING); var sc:int = NCNC.length; su = su - correlative; for (var k:int=0; k<sc && k<su; k++) { if (str.indexOf(NCNC[k].combL) >= 0) { //trace("Combinacion "+NCNC[k].combL +" Repeticiones "+NCNC[k].matches+" Sustituto "+SYMBOLUSE[correlative]); str = str.split(NCNC[k].combL).join(SYMBOLUSE[correlative]); FINALASOC.push(new Array(NCNC[k].combL,SYMBOLUSE[correlative])); correlative++; } else { NCNC.splice(k, 1); k--; sc--; } } result = CONTROL_CHAR[1] + FINALASOC.join(" ") + CONTROL_CHAR[1] + CONTROL_CHAR[0] + str; } else { result = CONTROL_CHAR[1] + CONTROL_CHAR[1] + CONTROL_CHAR[0] + str; } trace("Tamaño comprimido -> " + result.length); if(funStop != null){ funStop(); } return result; } public static function decompress( str:String ,funStart:Function = null,funStop:Function = null):String { if(funStart != null){ funStart(); } var controlChar1:String = str.substr(0,1);//recup el prim digit var ctrlStr:Array = str.substr(1,str.length).split(controlChar1);//borr el prim digit y sep desd el sig mism digit var ASOC:Array = ctrlStr[0].split(" ");//Asignamos la caden de control al asoc str = ctrlStr[1]; //Asignamos el resto de la cadena que es el documento comprimido var controlChar2:String = str.substr(0,1);//Recu el prim digit del doc comprimido para sus luego las comas str = str.substr(1,str.length);//Eliminamos el prim digit //for (var s:int=0; s<ASOC.length; s++) { //var SPL:Array = ASOC[s].split(","); //str = str.split(SPL[1]).join(SPL[0]); //} for (var s:int=ASOC.length-1; s>=0; s--) { var SPL:Array = ASOC[s].split(","); str = str.split(SPL[1]).join(SPL[0]); } var c:Array = str.split(" "); for (var n:int = 0; n < c.length; n++) { if (c[n].substr(0,1) == ",") { c[n] = c[int(c[n].substr(1,c[n].length))]; } } str = c.join(" "); if (str.indexOf(controlChar2) >= 0) { str = str.split(controlChar2).join(","); } if(funStop != null){ funStop(); } return str; } } } |
Utilización:
1 2 3 4 5 6 7 8 9 |
import seguridad.algoritmos.JVM; //Comprimiendo var ziped:String = JVM.compress("El texto de un documento grande"); trace(ziped); //Descomprimiendo var unziped:String = JVM.decompress(ziped); trace(unziped); |
Tambien es posible indicar dos funciones para saber cuando se inicio la compreison o descompresion y cuando se termino
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import seguridad.algoritmos.JVM; //Comprimiendo var ziped:String = JVM.compress("El texto de un documento grande",onCompressInit,onCompressFinish); trace(ziped); //Descomprimiendo var unziped:String = JVM.decompress(ziped,onDecompressInit,onDecompressFinish); trace(unziped); function onCompressInit():void{ Trace(Compresión iniciada); } function onCompressFinish():void{ Trace(Compresión finalizada); } function onDecompressInit():void{ Trace(Descompresión iniciada); } function onDecompressFinish():void{ Trace(Descompresión finalizada); } |
Clase homologa en php JVM.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
<?php /** * Compresses and decompresses AS3HtmlText with the JVM algorithm in PHP. * @author: javier Vicente medina * @web: xavirobot.com - jvm.bricobit.com */ function jvm_compress($str) { //echo "TAMAÑO SIN COMPRIMIR " . strlen($str) . "<br>"; $result; $CONTROL_CHAR = array(); $step = 0; $CHARS = iconv('UTF-8', 'windows-1252',"ÿþýüûúùø÷öõôóòñðïîíìëêéèçæåäãâáàßÞÝÜÛÚÙØ×ÖÕÔÓÒÑÐÏÎÍÌËÊÉÈÇÆÅÄÃÂÁÀ¿¾½¼»º¹¸·¶µ´³²±°¯®¬«ª©¨§¦¥¤£¢"); $CHARS_LENGTH = strlen($CHARS); for ($u = 0; $u<$CHARS_LENGTH; $u++) { $CONTROL_CHAR[$step] = $CHARS[$u]; if (strrpos($str,$CONTROL_CHAR[$step]) === false) { $step++; if ($step == 2) { break; } } } if (strrpos($str,",") >=0) { $str = implode($CONTROL_CHAR[0],explode(",",$str)); } $c = explode(" ",$str); $s = count($c); for ($n = 0; $n < $s; $n++) { $c[$n] = array($c[$n]); } for ($i = 0; $i < $s - 1; $i++) { if (!isset($c[$i][1]) && strlen($c[$i][0]) > 3) { for ($j = $i + 1; $j < $s; $j++) { if (!isset($c[$j][1])) { if ($c[$i][0] === $c[$j][0]) { $c[$j][0] = ""; $c[$j][1] = $i; } } } } } //Recuperamos todos los simbolos que no esten siendo utilizados en la cadena $SYMBOLUSE= array(); for ($f = 0; $f<$CHARS_LENGTH; $f++) { $letter = $CHARS[$f]; if ($letter!=$CONTROL_CHAR[0] && $letter!=$CONTROL_CHAR[1]) { $symbolSustitute = $CHARS[$f]; if (strrpos($str,$symbolSustitute) === false) { array_push($SYMBOLUSE,$symbolSustitute); } } } $su = count($SYMBOLUSE); //join $c +++ $arrLength = count($c); $strJoin; for($n=0;$n<$arrLength;$n++){ if(!isset($c[$n][1])){ $strJoin .= $c[$n][0] . " "; }else{ $strJoin .= "," . $c[$n][1] . " "; } } $str = trim($strJoin); //+++ join $c $NCNC = array(); $comb; $combMatches; $ManualMatch = array('</FONT></P></TEXTFORMAT><TEXTFORMAT','KERNING="','"><B>','</B>'); $mml = count($ManualMatch); $FINALASOC = array(); $correlative = 0; for ($mm=0; $mm<$mml; $mm++) { $comb = $ManualMatch[$mm]; $combMatches = substr_count($str, $comb); //$combMatches = count(explode($comb, $str))-1; if ($combMatches >0) { //array_push($NCNC,array('matches' => $combMatches+1, 'combL' => $comb)); $str = implode($SYMBOLUSE[$correlative],explode($comb,$str)); array_push($FINALASOC, array($comb,$SYMBOLUSE[$correlative])); $correlative++; } } $ABC = "áéíóúàèìòùabcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789"; $abcl = strlen($ABC); for ($q=0; $q<$abcl; $q++) { for ($p=0; $p<$abcl; $p++) { $comb = $ABC[$q] . $ABC[$p]; //$combMatches = count(explode($comb, $str))-1; $combMatches = substr_count($str, $comb); if ($combMatches >1) { array_push($NCNC, array('matches' => $combMatches, 'combL' => $comb)); } } } if (count($NCNC) > 0 || count($FINALASOC) >0) { //sustituimos los pares de letras con mayor numero de repeticiones por un simbolo usort($NCNC, "sortCompare");//ordenamos el par de letras que mas se repiten al principio $sc = count($NCNC); $su = $su - $correlative; for ($k=0; $k<$sc && $k<$su; $k++) { if (strrpos($str,$NCNC[$k]["combL"])) { $str = implode($SYMBOLUSE[$correlative],explode($NCNC[$k]["combL"],$str)); array_push($FINALASOC, array($NCNC[$k]["combL"],$SYMBOLUSE[$correlative])); $correlative++; } else { array_slice($NCNC,$k,1); $k--; $sc--; } } //join $FINALASOC +++ $arrLength = count($FINALASOC); $strJoin = ""; for($n=0;$n<$arrLength;$n++){ $strJoin .= $FINALASOC[$n][0] .",". $FINALASOC[$n][1] . " "; } $finalAsocJoined = trim($strJoin); //+++ join $FINALASOC $result = $CONTROL_CHAR[1] . $finalAsocJoined . $CONTROL_CHAR[1] . $CONTROL_CHAR[0] . $str; } else { $result = $CONTROL_CHAR[1] . $CONTROL_CHAR[1] . $CONTROL_CHAR[0] . $str; } //echo "TAMAÑO COMPRIMIDO " . strlen($str) . "<br>"; return $result; } function sortCompare($x, $y){ if ( $x['matches'] == $y['matches'] ) { return 0; }else if ( $x['matches'] > $y['matches'] ){ return -1; }else{ return 1; } } function jvm_decompress($str) { $controlChar1 = substr($str,0,1); $ctrlStr = explode($controlChar1,substr($str,1)); $ASOC= explode(" ",$ctrlStr[0]); $str = $ctrlStr[1]; $controlChar2 = substr($str,0,1); $str = substr($str,1); // for ($s=0; $s<count($ASOC); $s++) { //$SPL = explode(",",$ASOC[$s]); //$str = implode($SPL[0],explode($SPL[1],$str)); // } for ($s=count($ASOC)-1; $s>=0; $s--) { $SPL = explode(",",$ASOC[$s]); $str = implode($SPL[0],explode($SPL[1],$str)); } $c = explode(" ",$str); for ($n = 0; $n < count($c); $n++) { if (substr($c[$n],0,1) === ",") { $c[$n] = $c[substr($c[$n],1)]; } } $str = implode(" ",$c); if (strrpos($str,$controlChar2)) { $str = implode(",",explode($controlChar2,$str)); } return $str; } ?> |
Su uso es el mismo que en as3 pero no tiene las mejoras de poder especificar las funciones para saber cuando empezo la compresion o descompresion y cuando termino.
1 2 3 4 5 6 7 |
<?php require "jvm.php"; $ziped = jvm_compress("El texto de un documento grande"); echo $ziped; $unziped = jvm_decompress($ziped); echo $unziped ?> |