/Main_Page

::You must have ninja focus to complete your mission::NinjaFocus::

PHP Obfuscation

Views:

Here are some recipes for obscuring php code. (Yes, this is meant to be ironic).

If you are using PHP5 and writing object - orientated, polymorphic code, you can't use any of the free obfuscators out there on the internet. They break too much stuff.

use pobs (http://pobs.mywalhalla.net/) or something similar to strip whitespace and comments. http://www.fopo.com.ar/ looks like it does some really clever stuff but you have to upload your code to their server. Other than being an extremely tedious thing to do, I don't want to upload an entire application to them, who knows what will happen to the code.

Further reduce clarity with some text editor macros to strip the bits popbs missed like some new lines and spaces. Textmate is very good at this.

The code is difficult to read but that can easily be fixed with something like PHP Beautifier. The person wanting to see your code will still need to clear things up but it will be a quick operation. Leave out the closing PHP tag at the end of the file to give them another little thing to think about (PHP Beautifier will only clean code it finds between <?php and ?>.

This is OK, the comments are gone forever but people can still reformat the code and tools will help to put basic docblocks back and an generate documentation.

Now we need to add another step. This is still basic but it's a start on the road I had to go down. It will open a file, base64 encode the contents and save the file. It will also add a copy right notice to the top of the file. All you have to do is pass the name of the file to encode as an argument. This has the added benefit that if someone does start to change things, they will get useless error messages from php if they introduce any bugs. Chances are, the whole application will need to be decoded before it's practical to make changes.

If you try to obfuscate your php code you are an idiot.

This script will overwrite files in place. Work on a copy. Make a backup.

#!/opt/local/bin/php
<?php
$path = $_SERVER['argv'][1];
$debug = isset($_SERVER['argv'][2]) && $_SERVER['argv'][2] == 'debug' ? true : false;
$file = new SplFileInfo($path);
$file = $file->openFile('r+');
$contents = '';
while($file->valid()) $contents .= $file->fgets();
if ($debug) echo "Initial Contents = $contents \n\n";
$contents = substr($contents,5);
if ($debug) echo "Stripping PHP Tag = $contents\n\n";
$contents = base64_encode($contents);
if ($debug) echo "Encoding Contents = $contents\n\n";
$contents = "base64_decode('$contents')";
$contents = "eval($contents);";
$contents = "/* Copyright 2008 Example Co Ltd. Reverse engineering of this file is strictly prohibited. File protected by copyright law and provided under license. */ $contents";
$contents = "<?php $contents";
if ($debug) echo "Inserting Decoder = $contents\n\n";
$file->ftruncate(0);
$file->fseek(0);
$file->fwrite($contents);
$file->fflush();

Use your other shell tools if you need to go over a whole project of code. I use this simple bash loop or the find command:

$ for file in `ls *.php`;
> do echo "Encoding $file";
> ~/bin/base64 $file;
> done;

I usually have one file per class. This makes it easy to find your way around the code, each file is named the same as the class definition it contains. This also makes it easy to use spl_auto_load or __autoload to include files automatically.

To make it hard for people to see what the files are for we can rename them using an MD5 hash of their original name. You probably don't want to use this next step if you are not autoloading your class definitions. Also, your directory structure will still be saying a fair bit about the files and what they are for.

Heres a simple bash script to rename the files. Again, this will alter your existing files, so backup

$ for file in `ls *.php`;
> do newfile=`echo -n $file|md5`;
> mv $file $newfile;
> done;

Now you just need your autoload function to account for the new naming system with something like this:

<?php
function __autoload($className)
{
     require_once md5($className.'.php');
}


Old / Experimental

This is just a dump of various scripts that have lots of bugs.

More powerful (but incomplete) obfuscation script:

#!/opt/local/bin/php
<?php
class obs
{
	protected $charArrayNameMaps = array();
	protected $charHexes = array();
	protected $charHexStatements = array();
	protected $charOcts = array();
	protected $charOctStatements = array();
	protected $chars = array();
	protected $charStatements = array();
	protected $code = null;
	protected $evalAliases = array();
	protected $evil = array();
	protected $functions = array(
		'str_replace',
		'ereg_replace',
		'strtok',
		'md5',
		'call_user_func',
		'file_get_contents',
		'base64_decode',
		'strpos',
		'str_rot13',
		'putenv',
		'buscuits',
		'gzencode',
		'str_replace',
		'gzdecode',
		'ob_end_flush',
		'gzinflate',
		'gzdeflate',
		'exit',
		'ob_end_clean',
		'monkies',
		'getenv',
		'eval',
		'gzcompress',
		'assert',
		'constant',
		'gzuncompress',
		'die',
		'crypt',
		'bras',
		'wordwrap',	
		'gzrewind',
		'bzcompress',
		'define',
		'bzdecompress',
		'ob_get_contents',
		'get_file_contents',
		'strrev',
		'sha1',
		'md5_file',
		'levenshtein',
		'bastard',
		'chunk_split',
		'chr',
		'get_char_by_index',
		'asset_options',
		'obfuscate',
		'reverse_obfuscate',
		'pass',
		'str_rev'
		);
	protected $functionStatements = array();
	protected $message = "Copyright Acme Corp Ltd {date('Y')}. Reverse engineering of this file is strictly prohibited. File protected by copyright law and provided under license.";
	protected $obsFunctions = array();
	protected $obsVariables = array();
	protected $patterns = array(
			'classDeclaration' => "(?<=class\\s)[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*",
			'function' => "(?<![$])(?<=[\\s=\\+\\-\\*\\(\\)\\!\\>,;@])[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?=\\s*\\()",
			'functionDeclaration' => "(?<=function[\\s+])[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?=\\s*\\()",
			'string' => "(\".*?[^\\\\]\")|(\'.*?[^\\\\]\')|<<<(\\w+)(.|\\s)+?(\\4)\r\n",
			'variable' => "\\$[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*",
		);
	protected $sourceFile = null;
	protected $usedNames = array();
	protected $variables = array(
		'originalCode',
		'arrayChars',
		);

	
	public function __construct()
	{
		$this->buildCharArray();
		$this->shuffleCharArray();
		$this->buildCharHexArray();
		$this->buildCharOctArray();
		$this->mapNames();
		$this->buildEvil();
		$this->buildCharStatements();
		$this->buildFunctionStatements();
	}
	protected function buildCharArray()
	{
		for ($i = 32; $i <= 126; ++$i)
		{
			$this->chars[] = chr($i);
		}
	}
	protected function buildCharHexArray()
	{
		$this->charHexes = $this->chars;
		foreach ($this->charHexes as &$char)
		{
			$char = '\x'.dechex(ord($char));
		}
	}
	protected function buildCharOctArray()
	{
		$this->charOcts = $this->chars;
		foreach ($this->charOcts as &$char)
		{
			$char = '\\'.decoct(ord($char));
		}
	}
	protected function buildCharStatements()
	{
		$arrName1 = $this->obsVariables['arrayChars'][0];
		$arrName2 = $this->obsVariables['arrayChars'][1];
		$arrName3 = $this->obsVariables['arrayChars'][2];
		foreach ($this->chars as $index => $char)
		{
			$num = rand(1, 3);
			$arrName = 'arrName'.$num;
			$this->charArrayNameMaps[$index] = $num - 1;
			$statement = '$'.$$arrName.'['.$index.']=';
			if (rand(0, 1))
			{
				$statement .= "\"{$this->getCharOctByIndex($index)}\"";
			}
			else
			{
				$statement .= "\"{$this->getCharHexByIndex($index)}\"";
			}
			$this->charStatements[] = $statement.';';
		}
	}
	protected function buildCharExpressionForIndex($index)
	{
		$varName = $this->getCharVarNameForIndex($index);
		return '$'.$varName.'['.$index.']';
	}
	/**
	 * prepare an evil function which has been obfuscated
	 *
	 * @return void
	 * @author Kieran Whitbread
	 **/
	protected function buildEvil()
	{
		$thisEvil = $this->getUniqueObsName('thisEvil');
		$thisEvilArg = $this->getUniqueObsName('thisEvilArg');
		$evil = 'function '.$thisEvil.'($'.$thisEvilArg.'){return @eval($'.$thisEvilArg.');}';
		$evil = $this->obfuscateString($evil);
		$evil = "eval(\"$evil\");";
		$this->evil['name'] = $thisEvil;
		$this->evil['contents'] = $evil;
	}
	protected function buildFunctionDefinitionStatements()
	{
		$funcs = array();
		$funcs[] = 'pass';
		function cf_pass($that)
		{
			$pass = 'function pass($thing){return $thing;}';
			$pass = $that->obfuscateString($pass);
			$pass = "eval(\"$pass\");";
			return $pass;
		}
		$funcs[] = 'obfuscate';
		function cf_obfuscate($that)
		{
			$obfuscate = 'function obfuscate($string){$string=php_strip_whitespace($string);$newString="";for($i=0;$i<strlen($string);++$i){$newString.=get_char_by_index(ord(substr($string,$i,1)));}$string=$newString;$string=imap_binary($string);$string=strrev($string);return $string;}';
			$obfuscate = $that->obfuscateString($obfuscate);
			$obfuscate = "eval(\"$obfuscate\");";
			return $obfuscate;
		}
		$funcs[] = 'monkies';
		$this->evalAliases[] = 'monkies';
		function cf_monkies($that)
		{
			$evil = 'function monkies($toaster){return eval($toaster);}';
			$evil = $that->obfuscateString($evil);
			$evil = "eval(\"$evil\");";
			return $evil;
		}
		$funcs[] = 'reverse';
		function cf_reverse($that)
		{
			$reverse = 'function reverse_obfuscate($string){$string=strrev($string);$string=imap_base64($string);$newString="";foreach(explode("\\\",$string) as $ord){ $newString=char(octdec($ord));}$string=$newString;return $string;}';
			$reverse = $that->obfuscateString($reverse);
			$reverse = "eval(\"$reverse\");";
			return $reverse;
		}
		$funcs[] = 'bras';
		$this->evalAliases[] = 'bras';
		function cf_bras($that)
		{
			$evol = 'function bras($largekippers){return eval($largekippers);}';
			$evol = $that->obfuscateString($evol);
			$evol = "eval(\"$evol\");";
			return $evol;
		}
		$funcs[] = 'str_rev';
		function cf_str_rev($that)
		{
			$strrev = 'function str_rev($string){$string=strrev($string);return $string;}';
			$strrev = $that->obfuscateString($strrev);
			$strrev = "eval(\"$strrev\");";
			return $strrev;
		}
		$funcs[] = 'buscuits';
		$this->evalAliases[] = 'buscuits';
		function cf_buscuits($that)
		{
			$evel = 'function buscuits($turd){return eval($turd);}';
			$evel = $that->obfuscateString($evel);
			$evel = "eval(\"$evel\");";
			return $evel;
		}
		$funcs[] = 'bastard';
		$this->evalAliases[] = 'bastard';
		function cf_bastard($that)
		{
			$evel = 'function bastard($turd){return eval($turd);}';
			$evel = $that->obfuscateString($evel);
			$evel = "eval(\"$evel\");";
			return $evel;
		}
		shuffle($funcs);
		$encodedFunctions = '';
		foreach($funcs as $func)
		{
			$func = 'cf_'.$func;
			 $encodedFunctions .= $func($this);
		}		
		return $encodedFunctions;
	}
	protected function buildFunctionStatements()
	{
		$maxLen = 0;
		$numFunctions = count($this->functions);
		foreach ($this->functions as $index => $name)
		{
			if (strlen($name) > $maxLen) $maxLen = strlen($name);
		}
		for ($i = 0; $i < $maxLen; ++$i)
		{
			foreach ($this->functions as $name)
			{
				if (strlen($name) <= $i) continue;
				$obsName = $this->obsFunctions[$name];
				$char = $name[$i];
				$charIndex = $this->getCharIndex($char);
				$statement = '$'.$obsName.'.=';
				$statement .= $this->buildCharExpressionForIndex($charIndex);
				$statement .= ";";
				$this->functionStatements[] = $statement;
			}
		}
	}
	protected function getChar()
	{
		switch (rand(1, 2))
		{
			case 1:	return chr(rand(65, 90));
					break;
			case 2:	return chr(rand(97, 122));
					break;
		}
	}
	protected function getCharByIndex($index)
	{
		return $this->chars[$index];
	}
	protected function getCharHexByIndex($index)
	{
		return $this->charHexes[$index];
	}
	protected function getCharOctByIndex($index)
	{
		return $this->charOcts[$index];
	}
	protected function getCharIndex($char)
	{
		return array_search($char, $this->chars);
	}
	public function getCharStatements()
	{
		return implode("", $this->charStatements);
	}
	protected function getCharVarNameForIndex($index)
	{
		$varNameIndex = $this->charArrayNameMaps[$index];
		return $this->obsVariables['arrayChars'][$varNameIndex];
	}
	public function getEvil()
	{
		return $this->evil['contents'];
	}
	public function getFunctionStatements()
	{
		$statements = implode("", $this->functionStatements);
		$statements .= $this->buildFunctionDefinitionStatements();
		return $statements;
	}
	public function getObfuscatedCode()
	{
		$header = "<?php \r\n";
		$header .= "/* {$this->message} */ \r\n";
		$initVar = $this->getUniqueObsName('initVar');
		$init = '$'.$initVar.'="'.$this->obfuscateString('base64_decode').'";';
		// %s is a place holder where we will put the phase2 initialisation code,
		// the tamper check and the payload.
		$init .= '@eval($'.$initVar.'(\'%s\'));';
		
		// We're building in a check to make sure no one changes the initialisation code
		// or removes/edits the comment at the top of the file.
		// To do the check we are using a hash, and removing the place holder for the payload
		$checkContent = $header.$init;
		$checkContentLength = strlen($checkContent);
		$offset = $checkContentLength - 6;
		$hash = md5(substr_replace($checkContent, "", $offset, 2));
		$obsHash = $this->obfuscateString($hash);

		$md5Function = $this->obsFunctions['md5'];
		$eregReplaceFunction = $this->obsFunctions['ereg_replace'];
		$getFileContentsFunction = $this->obsFunctions['get_file_contents'];
		$strtokFunction = $this->obsFunctions['strtok'];
		$constantFunction = $this->obsFunctions['constant'];
		$strReplaceFunction = $this->obsFunctions['str_replace'];
		$pregMatchBase64 = $this->obfuscateString('\("[0-9A-Za-z\+/=]*"\)');
		$pregReplace = $this->obfuscateString('("")');
		$fileConstant = $this->obfuscateString("__FILE__");
		$fileVariable = $this->getUniqueObsName('fileVariable');
		//$checkCode = '$'.$fileVariable.'=$'.$constantFunction.'("'.$fileConstant.'");';
		//$checkCode .= 'if($'.$md5Function.'($'.$eregReplaceFunction.'("'.$pregMatchBase64.'","'.$pregReplace.'", $'.		$strReplaceFunction.'('.$pregMatchMatch.','.$pregReplace.','.$getFileContentsFunction.'('.$fileVariable.'))))=='.$obsHash.')';
		$phase2init = $this->getPhase2Code();
		//return sprintf($init, $phase2init);
		$payload = $this->getPayload();
		return sprintf('        '.$this->getEvil().'        '.$init, "     ".$phase2init."     ".$payload);
		
	}
	public function getPayload()
	{
		
		$inflateFunction = $this->obsFunctions['gzuncompress']; 
		$decodeFunction = $this->obsFunctions['base64_decode'];
		$rotFunction = $this->obsFunctions['str_rot13'];
		$reverseFunction = $this->obsFunctions['str_rev'];
		shuffle($this->evalAliases);
		$evalAlias = current($this->evalAliases);
		$evalFunction = $this->obsFunctions[$evalAlias];
		
		$rot1 = true;//rand(0,1);
		
		$rot2 = false;//rand(0,1);
		$reverse = rand(0, 1);
		
		$code = $this->code;
		
		$code = str_rot13($code);
			$code = gzcompress($code, 9);
				$code = base64_encode($code);
				$code = '$'.$decodeFunction.'("'.$code.'")';
			$code = '$'.$inflateFunction.'('.$code.')';
		$code = '$'.$rotFunction.'('.$code.')';
		
		$code = '$'.$decodeFunction.'('.$code.')';
		
		$code = '$'.$evalFunction.'('.$code.');';
		return $code;	
	}
	public function getPhase2Code()
	{
		$code = $this->getCharStatements();
		$code .= $this->getFunctionStatements();
		$code = gzcompress($code, 9);
		$code = base64_encode($code);
		$encodeFunctionVariable = '$'.$this->getUniqueObsName('encodeFunctionVariable');
		$thisEvil = $this->evil['name'];
		$toaster = $this->getUniqueObsName('toaster');
		$monkies = $this->getUniqueObsName('monkies');
		$evil = 'function '.$monkies.'($'.$toaster.'){return base64_decode($'.$toaster.');}';
		$evil = $this->obfuscateString($evil);
		$evil = "$thisEvil(\\\"$evil\\\");";
		$gzuncompressFunctionVariable = '$'.$this->getUniqueObsName('gzuncompressFunctionVariable');
		$gzuncompressName = $this->getUniqueObsName('gzuncompressName');
		$gzuncompressArg = $this->getUniqueObsName('gzuncompressArg');
		$gz = 'function '.$gzuncompressName.'($'.$gzuncompressArg.'){return gzuncompress($'.$gzuncompressArg.');}';
		$gz = $this->obfuscateString($gz);
		$gz = "$thisEvil(\"$gz\");";
		$code =  $gz.$evil.$gzuncompressFunctionVariable.'="'.$this->obfuscateString($gzuncompressName).'";'.$encodeFunctionVariable.'="'.$this->obfuscateString($monkies).'";@eval('.$gzuncompressFunctionVariable.'('.$encodeFunctionVariable.'("'.$code.'")))';
		return $code.';';
	}
	public function getTestStatements()
	{
		$statements = '';
		foreach ($this->obsFunctions as $key => $name)
		{
			 $statements .= "echo \"\$$name = $key = $name\r\n\";";
		}
		return $statements;
	}
	/**
	 * get an obfuscated name to use for a function or variable. Will be unique amongst all objects 
	 * generated by this instance of this class.
	 *
	 * @return void
	 * @author Kieran Whitbread
	 **/
	protected function getUniqueObsName($name)
	{
		$obsName = $this->getChar().md5($name.rand());
		if (!in_array($obsName, $this->usedNames))
		{
			$this->usedNames[] = $obsName;
			return $obsName;
		}
		else
		{
			return $this->getUniqueObsName($name);
		}
	}
	protected function makeObsFunctionNames($name)
	{
		$this->obsFunctions[$name] = $this->getUniqueObsName($name);
	}
	protected function makeObsVariableNames($name)
	{
		$obsNames = array();
		for ($i = 0; $i < 3; ++$i)
		{
			$obsNames[] = $this->getUniqueObsName($name);
		}
		$this->obsVariables[$name] = $obsNames;
	}
	protected function mapNames()
	{
		foreach ($this->functions as $name)
		{
			$this->makeObsFunctionNames($name);
		}
		foreach ($this->variables as $name)
		{
			$this->makeObsVariableNames($name);
		}
	}
	public function obfuscateString($string)
	{
		$len = strlen($string);
		$obsString = '';
		for ($i = 0; $i < $len; ++$i)
		{
			$char = $string[$i];
			$charIndex = $this->getCharIndex($char);
			if (rand(0, 1))
			{
				 $obsChar = $this->getCharHexByIndex($charIndex);
			}
			else
			{
				$obsChar = $this->getCharOctByIndex($charIndex);
			}
			$obsString .= strlen($obsChar) ? $obsChar : $chars;
		}
		return $obsString;
	}
	public function setCode($code)
	{
		/* $code = str_replace('<?php', '', $code);   */
		/* $code = str_replace('?>', '', $code);      */
		$code = '?>'.$code.'<?php';
		$notAllowed = $this->obfuscateString(' not allowed ');
		$code .= '?>'.md5(substr($code,10, 42).time()).'<?php die("'.$notAllowed.'"); ';
		$this->code = base64_encode($code);
	}
	public function setMessage($message)
	{
		$this->message = $message;
	}
	public function setSourceFile($filename)
	{
		if (!is_file($filename) && !is_readable($file))
		{
			throw RuntimeException("Cannot open file");
		}
		$this->sourceFile = $filename;
		$code = php_strip_whitespace($filename);
		error_log($code);
		$this->setCode($code);
	}
	protected function shuffleCharArray()
	{
		shuffle($this->chars);
	}
}


/*$contents = '
function doInit()
{
	$ohMy = "I really need a coffee\n";
	return $ohMy;
}
function doInit2()
{
	$ohMy2 = "I really need a coffee\n";
	return $ohMy2;
}
function doInit3()
{
	$ohMy3 = "I really need a coffee\n";
	return $ohMy3;
}
echo doInit();
echo doInit2();
echo doInit3();
$i=1;';

*/

/*$file = new SplFileInfo('test-code.php');
$file = $file->openFile('r');
$contents = '';
while($file->valid()) $contents .= $file->fgets();
*/

$path = isset($_SERVER['argv'][1]) && is_file($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : null;
if (is_null($path)) 
{
	echo "No File\r\n";
	exit(1);
}


$obs = new obs();
$obs->setSourceFile($path);

//$obs->getObfuscatedCode();
//die;
$evil = $obs->getEvil();
/*
error_log('=======');
error_log("Evil = $evil");
error_log('=======');*/


#$initcode = $obs->getPhase2Code();
#$code = $obs->getPayload();
#//$code = '';
#//echo $initcode."\r\n";
#//echo $code;
#echo $evil."\n\n".$initcode."\n\n".$code."\n\n";
#//var_dump($obs);
echo "\n\n"."\n\n".$obs->getPhase2Code()."\n\n"."\n\n";
//die;
echo "Begin Timing...\n\n";
$startTime = microtime();

echo "\n\nDoing Evil\n\n";
eval($evil);
echo "\n\nDoing init\n\n";
eval($initcode);
echo "\n\nDoing code\n\n";
eval($code);

$endTime = microtime();

echo "\r\n\r\n"."Size: ".strlen($initcode.$code)."\r\n\r\n";

echo "Time: ".($endTime - $startTime)."\r\n\r\n";
//echo $code;
die;

#$path = isset($_SERVER['argv'][1]) && is_file($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : null;
#if (is_null($path)) 
#{
#	echo "No File\r\n";
#	exit(1);
#}
#
#$debug = isset($_SERVER['argv'][2]) && $_SERVER['argv'][2] == 'debug' ? true : false;
#$file = new SplFileInfo($path);
#$file = $file->openFile('r+');
#$contents = '';
#while($file->valid()) $contents .= $file->fgets();
#if ($debug) echo "Initial Contents = $contents \r\n\r\n";
#$contents = substr($contents,5);
#if ($debug) echo "Stripping PHP Tag = $contents\r\n\r\n";
#$contents = base64_encode($contents);
#if ($debug) echo "Encoding Contents = $contents\r\n\r\n";
#$contents = "base64_decode('$contents')";
#$contents = "eval($contents);";
#$contents = "/* Copyright 2008 Acme Corp Ltd. Reverse engineering of this file is strictly prohibited. File protected by copyright law and provided under license. */ $contents";
#$contents = "<?php $contents";
#if ($debug) echo "Inserting Decoder = $contents\r\n\r\n";
#$file->ftruncate(0);
#$file->fseek(0);
#$file->fwrite($contents);
#$file->fflush();

#$startTime = microtime();
#include 'Downloads/Object_class.php';
#
#//include './Downloads/test-fops.php';
#
#$endTime = microtime();
#
#echo "Time: ".($endTime - $startTime)."\r\n\r\n";

Tokeniser and String Obfuscation

This script will help to obfuscate strings by encoding all characters as unicode ordinals in hex or oct


#!/opt/local/bin/php 
<?php
if (!defined('T_ML_COMMENT')) {
   define('T_ML_COMMENT', T_COMMENT);
} else {
   define('T_DOC_COMMENT', T_ML_COMMENT);
}

//$source = file_get_contents('./token-test.php');
$source = file_get_contents('/var/www/vhosts/example.com/application/Example.php');
$tokens = token_get_all($source);
//var_dump($tokens);
//die;
$last = '';
$newSource = '';
foreach ($tokens as $token) {
   if (is_string($token)) {
       // simple 1-character token
       $newSource .= $token;
		$last = $token;
   } else {
       // token array
       list($id, $text) = $token;

       switch ($id) { 
           case T_COMMENT: 
           case T_ML_COMMENT: // we've defined this
           case T_DOC_COMMENT: // and this
               // no action on comments or whitespace;
               break;
		   case T_WHITESPACE :
					if (!in_array($last, array(';','{','}',')','=',' ',',','[',']','.',"\t","\n","\r","\r\n"))) $newSource .= ' ';
				break;
			case T_CONSTANT_ENCAPSED_STRING	:
			case T_ENCAPSED_AND_WHITESPACE:
				$encText = '';
				$quoteType = null;
				$escaped = false;
				$embeddedQuote = false;
				if ($text[0] != "'" && $text[0] != '"') {
					$adjustment = 0;
					$start = 0;
				} else {
					$adjustment = 1;
					$start = 0;
				}
				for ($i = $start; $i < (strlen($text) - $adjustment); $i++)
				{
					if (is_null($quoteType) && $text[$i] == '"')
					{
						$quoteType = '"';
						//echo "GOT QUOTE TYPE = $quoteType from $text[0] in $text\n\n";
					}
					elseif (is_null($quoteType) && $text[$i] == "'")
					{
						$quoteType = "'";
						//echo "GOT QUOTE TYPE = $quoteType from $text[0] in $text\n\n";
					}
					else {
						if (is_null($quoteType)) $quoteType = false;
						if ($text[$i] == '\\')
						{
							$escaped = true;
							if ($text[$i + 1] == 'x')
							{
								$encText .= substr($text, $i, 4);
								$i = $i + 3;
							}
							elseif (preg_match('/\d/', $text[$i + 1]))
							{
								$encText .= substr($text, $i, 5);
								$i = $i + 4;
							}
							else
							{
								$encText .= substr($text, $i, 2);
								$i = $i + 1;
							}
						}
						elseif (substr($text, $i, 1) == '"' || substr($text, $i, 1) == "'") {
							$embeddedQuote = true;
						}
						else
						{
							$encText .= '\x'.dechex(ord($text[$i]));
						}
					}
				}
				if (!$embeddedQuote && !$escaped && $quoteType)
				{
					$newSource .= '"'.$encText.'"';
				}
				elseif (!$embeddedQuote && !$escaped) {
					$newSource .= $encText;
				}
				else
				{
					$newSource .= $text;
				}
				//$newSource .= $quoteType == '"' ? $quoteType.$encText.$quoteType : $text;
				break;
           default:
               // anything else -> output "as is"
               $newSource .= $text;
               break;
       }
	$last = $text;
   }
}
echo "\n".$newSource."\n\n";

Main Menu

Personal tools

Toolbox