PHP Classes
Icontem

File: Stegger.class.inc.php


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Warren Smith  >  Stegger  >  Stegger.class.inc.php  
File: Stegger.class.inc.php
Role: Class source
Content type: text/plain
Description: The main class
Class: Stegger
Hide encrypted data in images using steganography
 

Contents

Class file image Download
<?php

//+----------------------------------------------------------------------+
//| Stegger v0.6                                                         |
//+----------------------------------------------------------------------+
//| Copyright (c) 2006 Warren Smith ( smythinc 'at' gmail 'dot' com )    |
//+----------------------------------------------------------------------+
//| This library is free software; you can redistribute it and/or modify |
//| it under the terms of the GNU Lesser General Public License as       |
//| published by the Free Software Foundation; either version 2.1 of the |
//| License, or (at your option) any later version.                      |
//|                                                                      |
//| This library is distributed in the hope that it will be useful, but  |
//| WITHOUT ANY WARRANTY; without even the implied warranty of           |
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
//| Lesser General Public License for more details.                      |
//|                                                                      |
//| You should have received a copy of the GNU Lesser General Public     |
//| License along with this library; if not, write to the Free Software  |
//| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 |
//| USA                                                                  |
//+----------------------------------------------------------------------+
//| Simple is good.                                                      |
//+----------------------------------------------------------------------+
//

/*
  +----------------------------------------------------------------------+
  | Package: Stegger v0.6                                                |
  | Class  : Stegger                                                     |
  | Created: 03/08/2006                                                  |
  | Updated: 13/05/2008                                                  |
  +----------------------------------------------------------------------+
*/

 /*-------------*/
 /* C O N F I G */
 /*-------------*/

 // This is the public key (the one you give out) to encrypt or decrypt data with
 define('STEGGER_PUB_KEY', 'Where will the children play?');

 /*---------------*/
 /* D E F I N E S */
 /*---------------*/

 //

 /*-----------*/
 /* C L A S S */
 /*-----------*/

 class Stegger {

    /*-------------------*/
    /* V A R I A B L E S */
    /*-------------------*/

    // Public Properties

    /**
    * boolean
    *
    * A flag to determine if we should be verbose with output or not
    */
    var $Verbose = TRUE;

    // Private Properties

    /**
    * boolean
    *
    * A flag to determine if we are using a command line interface or not
    */
    var $CLI = FALSE;

    // Private Properties

    /**
    * object
    *
    * This is an object representing the image
    */
    var $Image;

    /**
    * object
    *
    * This is an object representing the main bit stream
    */
    var $BitStream;

    /**
    * string
    *
    * This is a unique boundry made up of 1's and 0's
    */
    var $BitBoundry;

    /**
    * array
    *
    * This is the secret data we are going to encode or have decoded
    */
    var $RawData = array();

    /*-------------------*/
    /* F U N C T I O N S */
    /*-------------------*/

    /*
      +------------------------------------------------------------------+
      | Constructor                                                      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Stegger(){

        // Run forever
        set_time_limit(0);

        // Setup the environment
        $this->SetEnvironment();

        // Create the bit stream object
        $this->BitStream = new BitStream();
    }

    // Public API Methods

    /*
      +------------------------------------------------------------------+
      | Encodes the $secretData into an $imageFile and encrypt with $key |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Put($secretData, $imageFile, $key = '', $outputFile = ''){

        // Get the start time
        $StartTime = microtime(TRUE);

        // Flush any previous bit streams
        $this->BitStream->FlushStream();

        // Tell the user we are loading the image
        $this->Info('Loading image..');

        // Attempt to load the image
        $this->Image = new Image($imageFile);

        // If we don't have an image
        if ($this->Image->EOF()){

            // Tell the user the problem
            $this->FatalError('Could not load the supplied image');

        } else {

            // Tell the user what we are doing
            $this->Info('Loading data..');

            // If we can't load the data they provided
            if (!$this->Input($secretData)){

                // Meh, I hate all this usability stuff
                $this->FatalError('Could not load the supplied data');

            } else {

                // Tell the user what we are doing
                $this->Info('Encrypting data..');

                // If we can't turn the data into an encrypted string
                if (!$this->RawToString($key)){

                    // Tell the user we couldn't encrypt the data
                    $this->FatalError('Could not encrypt the loaded data');

                } else {

                    // Tell the user what we are doing
                    $this->Info('Encoding data..');

                    // If we can't encode the data
                    if (!$this->StringToStream()){

                        // Tell the user about the error
                        $this->FatalError('Could not encode the loaded data');

                    } else {

                        // Tell the user what the next step is
                        $this->Info('Encoding image..');

                        // If we can't encode the image
                        if (!$this->StreamToPixels()){

                            // Tell the user there was a problem encoding the image
                            $this->FatalError('Could not encode the image');

                        } else {

                            // Tell the user what we are doing now
                            $this->Info('Saving image..');

                            // Output the image
                            $this->Image->Output($outputFile);

                            // As the kids say, wewt
                            $this->Success('Done in '.round(microtime(TRUE) - $StartTime).' seconds');
                        }
                    }
                }
            }
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will decode data from an image                              |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Get($imageFile, $key = '', $outputPath = ''){

        // Get the start time
        $StartTime = microtime(TRUE);

        // Flush any previous bit streams
        $this->BitStream->FlushStream();

        // Tell the user we are loading the image
        $this->Info('Loading image..');

        // Attempt to load the image
        $this->Image = new Image($imageFile);

        // If we don't have an image
        if ($this->Image->EOF()){

            // Tell the user the problem
            $this->FatalError('Could not load the supplied image');

        } else {

            // Tell the user we are about to read the image
            $this->Info('Reading image..');

            // Read the pixels into a bit stream
            $this->PixelsToStream();

            // If we don't have a bit stream
            if ($this->BitStream->EOF()){

                // Tell the user about the problems
                $this->FatalError('No hidden data found in the image');

            } else {

                // Tell the user we are decoding the data
                $this->Info('Decoding data..');

                // If we can't decode the bit stream into a string
                if (!$this->StreamToString()){

                    // Tell the user where it all went wrong
                    $this->FatalError('Could not decode the data');

                } else {

                    // Tell the user that the next step is to decrypt and decompress
                    $this->Info('Decrypting data..');

                    // If we can't decrypt and/or decompress
                    if (!$this->StringToRaw($key)){

                        // Tell the user about the problem
                        $this->FatalError('Could not decrypt data');

                    } else {

                        // If we have a problem outputting data
                        if (!$this->Output($outputPath)){

                            // Fatal Error
                            $this->FatalError('Too many errors to continue');

                        } else {

                            // We are done
                            $this->Success('Done in '.round(microtime(TRUE) - $StartTime).' seconds');
                        }
                    }
                }
            }
        }
    }

    // Input / Output Methods

    /*
      +------------------------------------------------------------------+
      | This will load the data to encode into the image                 |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function Input($data){

        // If the data looks like an array but NOT an uploaded file
        if (is_array($data) && !isset($data['tmp_name'])){

            // Loop through each element in the array
            foreach ($data as $Element){

                // Call ourselves again with the element
                $this->Input($Element);
            }

        } else {

            // Read the data into the raw data array
            $this->ReadToRaw($data);
        }

        // If we have elements in our raw data array
        if (is_array($this->RawData) && count($this->RawData > 0)){

            // Success
            return TRUE;

        } else {

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will set properties relating to our run time environment    |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function Output($path = ''){

        // If we have raw data to extract
        if (is_array($this->RawData) && count($this->RawData)){

            // If we have a path set
            if (strlen($path)){

                // If the path is not a directory
                if (!is_dir($path)){

                    // Error
                    $this->Error('The specified output path is not a directory');

                    // Failure
                    return FALSE;
                }

                // If the path is not writable
                if (!is_writable($path)){

                    // Error
                    $this->Error('The specified output path is not writable');

                    // Failure
                    return FALSE;
                }

                // While we have items in the raw data array
                while (count($this->RawData) > 0){

                    // If we can't write from the raw data
                    if (!$this->WriteFromRaw($path)){

                        // Error
                        $this->Error('Problem extracting files');

                        // Failure
                        return FALSE;
                    }

                }
                // If we got here we were probably successfull
                return TRUE;

            } else {

                // If we are in command line mode
                if ($this->CommandLineInterface()){

                    // Then tell the user we're gonna need an output path
                    $this->Error('You must specify an output path when using this tool from the command line');

                    // Failure
                    return FALSE;

                } else {

                    // Ok browser boy, since you aren't leet enough for a shell you only get one file or message
                    $Data = $this->WriteFromRaw('', TRUE);

                    // Handle each type of data differently
                    switch ($Data['type']){

                        // Message
                        case 'message':

                            // Send the appropriate mime type
                            header('Content-type: text/plain');

                            // Attempt to set a file name and get the browser to download
                            header('Content-Disposition: attachment; filename=message.txt');

                            // Output the message
                            echo $Data['message'];

                            // We should exit now so we don'taccidently send other stuff
                            exit();

                            // Yeah, I know, redundant
                            break;

                        // File
                        case 'file':

                            // Set the file name and get the browser to download
                            header('Content-Disposition: attachment; filename='.$Data['filename']);

                            // Output the file contents
                            echo $Data['file'];

                            // Don't execute anything below this
                            exit();

                            // Blah
                            break;
                    }

                    // If we get here we failed
                    return FALSE;
                }
            }

        } else {

            // Tell the user we had nothing to extract
            $this->Error('No hidden data to extract from image');

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | Reads a local or remote file or a message into the raw array     |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function ReadToRaw($data){

        // Figure out what kind of data we are dealing with here
        switch ($this->GetArgumentType($data)){

            // A message
            case 'message':

                // If we actually have a message
                if (strlen($data) > 0){

                    // Add the message to the final array
                    array_push($this->RawData, array('type' => 'message', 'message' => base64_encode(gzdeflate($data))));

                    // Success
                    return TRUE;
                }
                break;

            // An uploaded file
            case 'uploaded':

                // Attempt to read the temporary file into a variable
                $Contents = file_get_contents($data['tmp_name']);

                // If we actually have contents
                if (strlen($Contents) > 0){

                    // Add the data to the raw data array
                    array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $data['name']));

                    // Success
                    return TRUE;
                }
                break;

            // A glob style string
            case 'glob':

                // Loop through all of the glob matches
                foreach (glob($data) as $File){

                    // Attempt to read the file into memory
                    $Contents = file_get_contents($File);

                    // If we have contents
                    if (strlen($Contents) > 0){

                        // Add the data to the raw data array
                        array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $File));
                    }
                }

                // Were probably successfull
                return TRUE;

                break;

            // A path or url to a file
            case 'file':

                // Attempt to read the file into memory
                $Contents = file_get_contents($data);

                // If we have contents
                if (strlen($Contents) > 0){

                    // Add the data to the raw data array
                    array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $data));

                    // We were probably successfull
                    return TRUE;
                }
                break;
        }

        // If we got here we failed
        return FALSE;
    }

    /*
      +------------------------------------------------------------------+
      | This will pop another item off the raw data stack to output      |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function WriteFromRaw($path = '', $return = FALSE){

        // If we actually have shit to extract
        if (is_array($this->RawData) && count($this->RawData) > 0){

            // Pop another item off the stack
            $Data = array_pop($this->RawData);

            // Handle different data types differently
            switch ($Data['type']){

                // Message
                case 'message':

                    // If we aren't supposed to return
                    if ($return == FALSE){

                        // We don't write messages, we output them
                        $this->Info('The following message was embedded in the image');
                        $this->Info("\t".gzinflate(base64_decode($Data['message'])));

                        // Success
                        return TRUE;

                    } else {

                        // Decompress the message
                        $Data['message'] = gzinflate(base64_decode($Data['message']));

                        // Return the data type
                        return $Data;
                    }

                    // I don't know why I do this
                    break;

                // File
                case 'file':

                    // If we aren't returning
                    if ($return == FALSE){

                        // If we do not have a path
                        if (!strlen($path)){

                            // Then this was a waste of our time
                            return FALSE;

                        } else {

                            // Get some ifnormation about the file
                            $Info = pathinfo($Data['filename']);

                            // Get some information about our path
                            $Path = pathinfo($path);

                            // Attempt to open a file pointer to the output path
                            $Pointer = fopen($Path['dirname'].'/'.$Path['basename'].'/'.$Info['basename'], 'w+');

                            // If we have a pointer
                            if (is_resource($Pointer)){

                                // Write to the file
                                fwrite($Pointer, gzinflate(base64_decode($Data['file'])));

                                // Close the file
                                fclose($Pointer);

                                // I'm guessing everything went OK
                                return TRUE;

                            } else {

                                // Failure
                                return FALSE;
                            }

                        }

                    } else {

                        // Just decompress and decode the file contents
                        $Data['file'] = gzinflate(base64_decode($Data['file']));

                        // And return it
                        return $Data;
                    }

                    //
                    break;
            }

        } else {

            // Meh
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will encode and compress a raw data array                   |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function RawToString($key = ''){

        // If we actually have a data array
        if (is_array($this->RawData) && count($this->RawData) > 0){

            // Serialize our data array
            $this->DataString = serialize($this->RawData);

            // Instantiate the Secrypt object
            $Secrypt = new Secrypt();

            // If we can encrypt the data
            if ($Secrypt->Encrypt($this->DataString, $key)){

                // Then update the data string
                $this->DataString = $Secrypt->Data;

                // We are done with the raw data and encryption class
                $this->RawData = array(); unset($Secrypt);

                // Loop untill we have a valid bit boundry
                while (strstr($this->DataString, $Boundry) || strlen($Boundry) <= 0){

                    // Generate a new 24 bit boundry
                    $Boundry = chr(rand(33, 127)).chr(rand(33, 127)).chr(rand(33, 127));
                }

                // Reset the bit boundry
                $this->BitBoundry = '';

                // Loop through each character in the new boundry
                for ($i = 0; $i < 3; $i++){

                    // Add this to the bit boundry
                    $this->BitBoundry .= str_pad(decbin(ord($Boundry[$i])), 8, '0', STR_PAD_LEFT);
                }

                // Success
                return TRUE;

            } else {

                // We have no data string
                $this->DataString = '';

                // Failure
                return FALSE;
            }

        } else {

            // Nothing to do
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will decompress and decode a string into a raw data array   |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function StringToRaw($key = ''){

        // If we actually have an encoded data string
        if (is_string($this->DataString) && strlen($this->DataString) > 0){

            // Create a new instance of the Secrypt object
            $Secrypt = new Secrypt();

            // If we can decrypt the string
            if ($Secrypt->Decrypt($this->DataString, $key)){

                // Then unserialize the data array
                $this->RawData = unserialize($Secrypt->Data);

                // If we have a raw data array
                if (is_array($this->RawData) && count($this->RawData) > 0){

                    // Then we did it
                    return TRUE;

                } else {

                    // Failure
                    return FALSE;
                }

            } else {

                // Failure
                return FALSE;
            }

        } else {

            // Nothing to do
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will turn a bit stream into a data string                   |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function StreamToString(){

        // Make sure we have an empty data string
        $this->DataString = '';

        // Loop untill the end of the bit stream
        while (!$this->BitStream->EOF()){

            // Add the character representation for the next 8 bits to our data string
            $this->DataString .= chr(bindec($this->BitStream->Read(8)));
        }

        // If we have a data string
        if (strlen($this->DataString) > 0){

            // Trim any spare spaces off the string
            $this->DataString = trim($this->DataString, ' ');

            // Success
            return TRUE;

        } else {

            // Summn went wrong
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will turn an encoded data string into a bit sequence        |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function StringToStream(){

        // Flush the bit stream
        $this->BitStream->FlushStream();

        // If we have a data string that will fit in the image
        if ((strlen($this->DataString) * 8) < (($this->Image->CountPixels() - 6) * 3)){

            // While the length of the string is not cleanly divisible by 3
            while (strlen($this->DataString) % 3 > 0){

                // Add a white space character to the data string
                $this->DataString .= ' ';
            }

            // While we still have a data string
            while (strlen($this->DataString) > 0){

                // Write the next chunk of characters to the bit stream
                $this->BitStream->Write(substr($this->DataString, 0, 1));

                // Remove the first character from the data string
                $this->DataString = substr($this->DataString, 1);
            }

            // Success
            return TRUE;

        } else {

            // Work out how many bytes this image can hold
            $Capacity = round(($this->Image->CountPixels() * 3) / 8);

            // If we have less than a kilobyte
            if ($Capacity < 1024){

                // Make the capacity human readable
                $Capacity = $Capacity.' bytes';

            // If the capacity is smaller than a megabyte
            } elseif ($Capacity < 1048576){

                // Make the capacity human readable
                $Capacity = round($Capacity / 1024, 2).' KB';

            // The capacity is 1 megabyte or over
            } else {

                // Make the capacity human readable
                $Capacity = round(($Capacity / 1024) / 1024, 2).' MB';
            }

            // Tell the user why the problem occurred
            $this->Error('That image is not large enough to store that much data');

            // Now go over the top and tell the user how they can fix it
            $this->Error('The image you supplied can only hold '.$Capacity.' of data');

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will read pixels to obtain a bit stream                     |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function PixelsToStream(){

        // Make a new bit stream for the image
        $BitStream = new BitStream($this->Image->GetBoundry());

        // Move to the start pixel
        $this->Image->StartPixel();

        // While we have bits and pixels
        while (!$this->Image->EOF() && !$BitStream->EOF()){

            // Get the current pixels RGB value
            $Pixel = $this->Image->GetPixel();

            // Write the pixel data to the bit stream
            $BitStream->Write($Pixel);

            // Move to the next pixel
            $this->Image->NextPixel();
        }

        // If we got to the end of the image
        if ($this->Image->EOF()){

            // Then we never found our secret data
            $BitStream->Stream = '';
        }

        // Overwrite the main bit stream with our new one
        $this->BitStream = $BitStream;
    }

    /*
      +------------------------------------------------------------------+
      | This will write a bit stream to pixels                           |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function StreamToPixels(){

        // Move to the start pixel
        $this->Image->StartPixel();

        // While we have bits and pixels
        while (!$this->Image->EOF() && !$this->BitStream->EOF()){

            // Read the next 3 bits from the bit stream
            $Bits = $this->BitStream->Read(3);

            // Write those 3 bits to the current pixel
            $this->Image->SetPixel($Bits);

            // Move to the next pixel
            $this->Image->NextPixel();
        }

        // Set the end bit boundry
        $this->Image->SetBoundry($this->BitBoundry);

        // Move to the first pixel
        $this->Image->FirstPixel();

        // Set the first bit boundry
        $this->Image->SetBoundry($this->BitBoundry);

        // If we got here we probably succeeded
        return TRUE;
    }

    // Enviromental Methods

    /*
      +------------------------------------------------------------------+
      | This will set properties relating to our run time environment    |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function SetEnvironment(){

        // If we have a REQUEST_METHOD
        if ($_SERVER['REQUEST_METHOD']){

            // Then we are probably being called from the web
            $this->CLI = FALSE;

            // Turn verbose output off
            $this->Verbose = FALSE;

        } else {

            // We are being run as a command line (or possibly compiled) app
            $this->CLI = TRUE;

            // Turn verbose output on
            $this->Verbose = TRUE;

            // Make sure we have implicit flush set to on
            ob_implicit_flush(1);
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will determine if we are using a command line interface     |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function CommandLineInterface(){

        // If the command line interface flag is set
        if ($this->CLI){

            // Then we are probably using a command line interface
            return TRUE;

        } else {

            // Not a command line interface
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will attempt to figure out what an argument represents      |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function GetArgumentType($argument){

        // If this is looks like an uploaded file
        if (is_array($argument) && isset($argument['tmp_name'])){

            // Then it probably is one
            return 'uploaded';

        // If this looks like a local file
        } elseif (file_exists($argument)){

            // Handle as a file
            return 'file';

        // If this looks like an external resource (TODO: Do this properly)
        } elseif (strstr($argument, '://')){

            // Handle as a file
            return 'file';

        // If the argument contains an asterix (TODO: Check the validity of the path)
        } elseif (strstr($argument, '*') && ($argument[0] == '.' || $argument[0] == '/')){

            // Then I'm guessing it is a glob style string
            return 'glob';

        // Everything else
        } else {

            // Treat it as a normal message
            return 'message';
        }
    }

    // Message Methods

    /*
      +------------------------------------------------------------------+
      | Print out an error message to the user and exit                  |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function FatalError($msg){

        // First we show the error message to the user
        $this->Error('Fatal Error: '.$msg);

        // Now we exit
        exit(-1);
    }

    /*
      +------------------------------------------------------------------+
      | Print out an error message to the user                           |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Error($msg){

        // If we are running as a command line application
        if ($this->CommandLineInterface()){

            // Just show the message a little formatted for the command line
            echo '[-] '.$msg.".\n";

        } else {

            // Show the error formatted for the web
            echo '<strong>Error:</strong> '.htmlspecialchars($msg).'<br />';
        }
    }

    /*
      +------------------------------------------------------------------+
      | Print out a success message to the user                          |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Success($msg){

        // If we are in verbose mode
        if ($this->Verbose){

            // If we are running as a command line application
            if ($this->CommandLineInterface()){

                // Just show the message a little formatted for the command line
                echo '[+] '.$msg.".\n";

            } else {

                // Show the message formatted for the web
                echo '<strong>Success:</strong> '.htmlspecialchars($msg).'<br />';
            }
        }
    }

    /*
      +------------------------------------------------------------------+
      | Print out an informative message to the user                     |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Info($msg){

        // If we are in verbose mode
        if ($this->Verbose){

            // If we are running as a command line application
            if ($this->CommandLineInterface()){

                // Just show the message a little formatted for the command line
                echo '[i] '.$msg.".\n";

            } else {

                // Show the message formatted for the web
                echo '<strong>Info:</strong> '.htmlspecialchars($msg).'<br />';
            }
        }
    }
}

/*
  +----------------------------------------------------------------------+
  | Package: Stegger v0.5                                                |
  | Class  : BitStream                                                   |
  | Created: 03/08/2006                                                  |
  +----------------------------------------------------------------------+
*/

class BitStream {

    /*-------------------*/
    /* V A R I A B L E S */
    /*-------------------*/

    /**
    * string
    *
    * This is a string of 1's and 0's representing binary data
    */
    var $Stream = '';

    /**
    * string
    *
    * This is a string of 1's and 0's representing the bit boundry
    */
    var $Boundry = '';

    /**
    * boolean
    *
    * This is a flag to determine if the class is still new or not
    */
    var $Fresh = TRUE;

    /*-------------------*/
    /* F U N C T I O N S */
    /*-------------------*/

    /*
      +------------------------------------------------------------------+
      | Constructor                                                      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function BitStream($bitBoundry = ''){

        // If we have a bit boundry, use it
        if ($bitBoundry) $this->Boundry = $bitBoundry;
    }


    /*
      +------------------------------------------------------------------+
      | This will read $number bits from the bit stream                  |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function Read($number = 8){

        // If we are not on the end of the bit stream
        if (strlen($this->Stream) > 0){

            // Grab the chunk of bits from the bit stream
            $return = substr($this->Stream, 0, $number);

            // Remove the chunk of bits from the bit stream
            $this->Stream = substr($this->Stream, $number);

            // Return the chunk of bits
            return $return;

        } else {

            // Nothing to return
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will write data to the bit stream                           |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Write($data, $binary = FALSE){

        // If we have binary data
        if ($binary){

            // Then just add it raw
            $this->Stream .= $data;

        } else {

            // Handle different data types differently
            switch (gettype($data)){

                // String
                case 'string':

                    // Loop through each character in the string
                    for ($i = 0; $i < strlen($data); $i++){

                        // Add the bit representation for this character to the bit stream
                        $this->Stream .= str_pad(decbin(ord($data[$i])), 8, '0', STR_PAD_LEFT);
                    }
                    break;

                // Integer
                case 'integer':

                    // Add the bit representation for this character to the bit stream
                    $this->Stream .= str_pad(decbin($data), 8, '0', STR_PAD_LEFT);
                    break;

                // Boolean
                case 'boolean':

                    // If the boolean is true
                    if ($data == TRUE){

                        // Then add a 1 to the bit stream
                        $this->Stream .= '1';

                    } else {

                        // Add a 0 to the bit stream
                        $this->Stream .= '0';
                    }
                    break;

                // Array of RGB values
                case 'array':

                    // Loop through each primary colour in this RGB array
                    foreach ($data as $PrimaryColour){

                        // Add the bit value of this integer
                        $this->Stream .= (int) $PrimaryColour % 2;
                    }
                    break;
            }
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will determine if we have hit the end of the bit stream     |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function EOF(){

        // If we have not ran any methods yet
        if ($this->Fresh){

            // We are no longer fresh
            $this->Fresh = FALSE;

            // But we are not at the end of the file either
            return FALSE;
        }

        // If we have a bit of stream left
        if (strlen($this->Stream) > 0){

            // If we have a bit boundry
            if (strlen($this->Boundry)){

                // If we have found our bit boundry
                if (substr($this->Stream, -24) == $this->Boundry){

                    // Then we remove the boundry from the bit stream
                    $this->Stream = substr($this->Stream, 0, -24);

                    // We hit the end of the stream
                    return TRUE;

                } else {

                    // We are not at the end of the stream
                    return FALSE;
                }

            } else {

                // Not at the end
                return FALSE;
            }

        } else {

            // Yeah, we're at the end
            return TRUE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will flush out the bit stream (reset it)                    |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function FlushStream(){

        // Reset the stream
        $this->Stream = '';
    }
}

/*
  +----------------------------------------------------------------------+
  | Package: Stegger v0.5                                                |
  | Class  : Image                                                       |
  | Created: 03/08/2006                                                  |
  +----------------------------------------------------------------------+
*/

class Image {

    /*-------------------*/
    /* V A R I A B L E S */
    /*-------------------*/

    /**
    * resource
    *
    * This is the main image canvas we are reading from or writing too
    */
    var $Canvas;

    /**
    * string
    *
    * The name of the image we are encoding to or decoding from
    */
    var $Name = '';

    /**
    * integer
    *
    * The main image canvas' width
    */
    var $Width = 0;

    /**
    * integer
    *
    * The main image canvas' height
    */
    var $Height = 0;

    /**
    * array
    *
    * This is an array containing the x and y co-ordinate's of the current pixel
    */
    var $PixelPointer = array('x' => 0, 'y' => 0);

    /**
    * boolean
    *
    * Determines if we are at the end of the image or not
    */
    var $EOF = TRUE;

    /*-------------------*/
    /* F U N C T I O N S */
    /*-------------------*/

    /*
      +------------------------------------------------------------------+
      | Constructor                                                      |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function Image($image){

        // If we have an image
        if ($image){

            // Load it
            $this->Load($image);

        } else {

            // Failure
            return FALSE;
        }
    }


    /*
      +------------------------------------------------------------------+
      | This will load an image as a resource                            |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function Load($image){

        // If the image looks like it was uploaded
        if (is_array($image) && isset($image['tmp_name'])){

            // Set the default output image name using the original file name
            $this->SetName($image['name']);

            // Create a canvas for this image
            $this->CreateCanvas($image['tmp_name'], $image['name']);

        } else {

            // Set the default output image name using the path or url to the image
            $this->SetName($image);

            // Create a canvas for this image
            $this->CreateCanvas($image);
        }

        // If we actually have a canvas at this point
        if (is_resource($this->Canvas)){

            // We are not at the end of the file
            $this->EOF = FALSE;

            // Clear the canvas
            $this->ClearCanvas();

            // Move to the first pixel
            $this->FirstPixel();

            // Success
            return TRUE;

        } else {

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | Creates an image canvas resource from an image url or path       |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function CreateCanvas($image, $name = ''){

        // If we don't have the original name, then the image contains the name
        if (!$name) $name = $image;


        // Handle each image type differently
        switch ($this->GetImageType($name)){

            // JPG
            case 'JPG':

                // Create a canvas from the JPG
                $this->Canvas = imagecreatefromjpeg($image); break;

            // PNG
            case 'PNG':

                // Create a canvas from the PNG
                $this->Canvas = imagecreatefrompng($image); break;

            // GIF
            case 'GIF':

                // Create a canvas from the GIF
                $this->Canvas = imagecreatefromgif($image); break;

            // Not Supported
            default:

                // Nothing else we can do
                return;
        }

        // If we have an image canvas
        if (is_resource($this->Canvas)){

            // Get the images width
            $this->Width = imagesx($this->Canvas);

            // Get the images height
            $this->Height = imagesy($this->Canvas);

            // We are not at the end of the file
            $this->EOF = FALSE;

        } else {

            // We are at the end of the file
            $this->EOF = TRUE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will copy the image on to a fresh canvas                    |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function ClearCanvas(){

        // Create a new true colour canvas based on our images dimensions
        $Canvas = imagecreatetruecolor($this->Width, $this->Height);

        // If we have a canvas and an image
        if (is_resource($Canvas) && is_resource($this->Canvas)){

            // Make sure alpha blending is off
            imagealphablending($Canvas, FALSE);

            // Copy the contents of the original canvas to the new one
            imagecopy($Canvas, $this->Canvas, 0, 0, 0, 0, $this->Width, $this->Height);

            // Overwrite the old canvas with the newly prepaired one
            $this->Canvas = $Canvas;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will output the current image to a file or the browser      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Output($outputFile = ''){

        // If we have an output file specified
        if ($outputFile){

            // Set the output image name
            $this->SetName($outputFile);
        }

        // If we are serving to a browser
        if ($_SERVER['REQUEST_METHOD']){

            // Make sure the browser knows this is a PNG image
            header('Content-type: image/png');

            // Try get the browser to download the image as our name
            header('Content-Disposition: attachment; filename='.$this->Name);

            // Output the image to the browser
            imagepng($this->Canvas);

        } else {

            // Get some information about the output path
            $Info = pathinfo($outputFile);

            // Write the image to the file name specified
            imagepng($this->Canvas, $Info['dirname'].'/'.$this->Name);
        }

        // Destroy the canvas
        imagedestroy($this->Canvas);
    }

    /*
      +------------------------------------------------------------------+
      | This will get the image type from a URL or path to an image      |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function GetImageType($image){

        // Get some information about the path, URL or image name
        $Info = pathinfo($image);

        // Handle each extension type differently
        switch (strtolower($Info['extension'])){

            // JPEG
            case 'jpg':
            case 'jpeg':

                // We are dealing with a JPG
                return 'JPG';

            // GIF
            case 'gif':

                // We are dealing with a GIF
                return 'GIF';

            // PNG
            case 'png':

                // We are dealing with a PNG
                return 'PNG';

            // *
            default:

                // No idea what the hell this is
                return '';
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will get the RGB value of the current pixel                 |
      |                                                                  |
      | @return array                                                    |
      +------------------------------------------------------------------+
    */

    function GetPixel(){

        // Get the (32 bit) RGB value from the current image
        $RGB = imagecolorat($this->Canvas, $this->PixelPointer['x'], $this->PixelPointer['y']);

        // Obtain the individual values for each primary colour
        $R = ($RGB >> 16) & 0xFF;
        $G = ($RGB >>  8) & 0xFF;
        $B = ($RGB >>  0) & 0xFF;

        // Return the individual RGB values in an array
        return array($R, $G, $B);
    }

    /*
      +------------------------------------------------------------------+
      | This will set the RGB value of the current array                 |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function SetPixel($rgb){

        // If this looks like a couple of bits
        if (is_string($rgb) && strlen($rgb) == 3){

            // Get the RGB value of the current pixel
            $RGB = $this->GetPixel();

            // Loop through each primary colour in this pixel
            for ($i = 0; $i < 3; $i++){

                // If the current char of our binary string is a 1
                if ($rgb[$i] == '1'){

                    // If the current colour value isn't odd
                    if ($RGB[$i] % 2 != 1){

                        // Increment it
                        $RGB[$i]++;
                    }

                } else {

                    // If the current colour valie isn't even
                    if ($RGB[$i] % 2 != 0){

                        // Decrease it
                        $RGB[$i]--;
                    }
                }
            }

            // Call ourselves again with the RGB array
            $this->SetPixel($RGB);

            // And thats all there is to it
            return TRUE;
        }

        // If we have a full RGB array
        if (is_array($rgb) && count($rgb) == 3){

            // Allocate the colour to the image
            $Colour = imagecolorallocate($this->Canvas, $rgb[0], $rgb[1], $rgb[2]);

            // Assign the colour to the current pixel
            imagesetpixel($this->Canvas, $this->PixelPointer['x'], $this->PixelPointer['y'], $Colour);

            // We're done here
            return TRUE;
        }

        // If we get here we failed
        return FALSE;
    }

    /*
      +------------------------------------------------------------------+
      | This will count the total number of pixels on the canvas         |
      |                                                                  |
      | @return integer                                                  |
      +------------------------------------------------------------------+
    */

    function CountPixels(){

        // Return the width multiplied by the height
        return round($this->Height * $this->Width);
    }

    /*
      +------------------------------------------------------------------+
      | This will move the pixel position to the first pixel             |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function FirstPixel(){

        // Reset the pixel pointer
        $this->PixelPointer['x'] = ($this->Width - 1);
        $this->PixelPointer['y'] = ($this->Height - 1);
    }

    /*
      +------------------------------------------------------------------+
      | This will move the pixel pointer to the start of the data        |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function StartPixel(){

        // The data starts 24 bits in (3 bytes)
        $this->PixelPointer['x'] = ($this->Width - 1) - 8;
        $this->PixelPointer['y'] = ($this->Height - 1);
    }

    /*
      +------------------------------------------------------------------+
      | This will move to the next pixel                                 |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function NextPixel(){

        // If we are on the last column
        if ($this->PixelPointer['x'] <= 0){

            // If we are on the last row of pixels
            if ($this->PixelPointer['y'] <= 0){

                // We are at the end of the file
                $this->EOF = TRUE;

                // So we can't go any further
                return $this->EOF;

            } else {

                // Move to the next row
                $this->PixelPointer['y']--;

                // Move to the first column of the new row
                $this->PixelPointer['x'] = ($this->Width - 1);
            }

        } else {

            // Move to the next column
            $this->PixelPointer['x']--;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will move to the previous pixel                             |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function PrevPixel(){

        // If we are on the first column
        if ($this->PixelPointer['x'] >= ($this->Width - 1)){

            // If we are on the first row of pixels
            if ($this->PixelPointer['y'] >= ($this->Height - 1)){

                // Then we can't go back any further
                return;

            } else {

                // Move to the previous row
                $this->PixelPointer['y']++;

                // Move to the last column of the current row
                $this->PixelPointer['x'] = 0;
            }

        } else {

            // Move to the previous column
            $this->PixelPointer['x']++;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will get the boundry pattern for the bit stream             |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function GetBoundry(){

        // Backup the current pixel pointer
        $PixelPointer = $this->PixelPointer;

        // Move to the first pixel
        $this->FirstPixel();

        // Go through the first 8 pixels (24 bits)
        for ($i = 0; $i < 8; $i++){

            // Get this pixels RGB value
            $Pixel = $this->GetPixel();

            // Loop through each primary colour in this
            foreach ($Pixel as $PrimaryColour){

                // Add the bit value of this number to the final string
                $return .= (int) $PrimaryColour % 2;
            }

            // Move to the next pixel
            $this->NextPixel();
        }

        // Move the pixel pointer back where it was
        $this->PixelPointer = $PixelPointer;

        // Return the final value
        return $return;
    }

    /*
      +------------------------------------------------------------------+
      | This sets the bit boundry from the current pixel position        |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function SetBoundry($boundry){

        // If we have at least 3 bytes of data (24 bits)
        if (strlen($boundry) >= 24){

            // Initiate the bit counter
            $b = 0;

            // Loop through 8 pixels from our current position
            for ($i = 0; $i < 8; $i++){

                // Get the RGB value of the current value
                $RGB = $this->GetPixel();

                // Loop through each primary colour in the RGB array
                for ($j = 0; $j < 3; $j++){

                    // Get the next bit from the binary string
                    $Bit = $boundry[$b];

                    // Figure out which kind of bit this is
                    switch ($Bit){

                        // 1
                        case '1':

                            // If this colour is not an odd number
                            if ($RGB[$j] % 2 != 1){

                                // Then increase it
                                $RGB[$j]++;
                            }

                            break;

                        // 0
                        case '0':
                            // If this colour is not represented by an even number
                            if ($RGB[$j] % 2 != 0){

                                // Decrease it
                                $RGB[$j]--;
                            }

                            break;
                    }

                    // Increment the bit counter
                    $b++;
                }

                // Set the pixel to our new RGB array
                $this->SetPixel($RGB);

                // Move to the next pixel
                $this->NextPixel();
            }
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will set the name of the image we are going to output       |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function SetName($image){

        // Get some information about the image filename, path or url
        $Info = pathinfo($image);

        // If we have an extension
        if (strlen($Info['extension']) > 0){

            // If the extension is not a PNG
            if (strtolower($Info['extension']) != 'png'){

                // Change the extension to a PNG
                $Info['basename'] = str_replace('.'.$Info['extension'], '.png', $Info['basename']);
            }

        } else {

            // If we have a basename
            if (strlen($Info['basename']) > 0){

                // Then append our extension to it
                $Info['basename'] .= '.png';

            } else {

                // This guy isn't giving us much choice
                $Info['basename'] = 'encoded.png';
            }
        }

        // Set the image name to the base name
        $this->Name = $Info['basename'];
    }

    /*
      +------------------------------------------------------------------+
      | This will test for the end of the file (image)                   |
      |                                                                  |
      | @return boolean                                                  |
      +------------------------------------------------------------------+
    */

    function EOF(){

        // Return the end of file property
        return $this->EOF;
    }
}

/*
  +----------------------------------------------------------------------+
  | Package: Stegger v0.5                                                |
  | Class  : Secrypt                                                     |
  | Created: 23/07/2006                                                  |
  +----------------------------------------------------------------------+
*/

class Secrypt {

    /*-------------------*/
    /* V A R I A B L E S */
    /*-------------------*/

    // Public Properties

    /**
    * array
    *
    * This is the array of keys we use to encrypt or decrypt data
    */
    var $Keys = array('public' => '', 'private' => '', 'xfactor' => '', 'yfactor' => '', 'zfactor' => '');

    /**
    * string
    *
    * This holds the data after it has been successfully encrypted or decrypted
    */
    var $Data = '';

    /**
    * boolean
    *
    * Determines if we can zip the contents or not
    */
    var $Zip = TRUE;

    /**
    * array
    *
    * All the error messages in an array
    */
    var $Errors = array();

    // Private Properties

    /**
    * array
    *
    * An array that holds each of our base64 compatible charsets
    */
    var $Locks = array();

    /*-------------------*/
    /* F U N C T I O N S */
    /*-------------------*/

    /*
      +------------------------------------------------------------------+
      | Constructor                                                      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Secrypt(){

        // If we  can't zip
        if (!function_exists('gzdeflate')){

            // Then we don't zip
            $this->Zip = FALSE;
        }

        // Run forever
        set_time_limit(0);

        // Reset the lock
        $this->ResetLock();
    }

    // Public API Methods

    /*
      +------------------------------------------------------------------+
      | This will encrypt $data against the $privateKey and $publicKey   |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function Encrypt($data, $privateKey = '', $publicKey = STEGGER_PUB_KEY){

        // Insert the keys
        $this->InsertKeys($privateKey, $publicKey);

        // Turn all the keys
        $this->TurnKey();

        // Locketh the data
        return $this->Lock($data);
    }

    /*
      +------------------------------------------------------------------+
      | This will decrypt $data against the $privateKey and $publicKey   |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function Decrypt($data, $privateKey = '', $publicKey = STEGGER_PUB_KEY){

        // Insert the keys
        $this->InsertKeys($privateKey, $publicKey);

        // Turn all the keys
        $this->TurnKey();

        // Unlock the data and return the results
        return $this->Unlock($data);
    }

    // Key Methods

    /*
      +------------------------------------------------------------------+
      | This gets a reference to the key that fits in $lockType          |
      |                                                                  |
      | @return reference                                                |
      +------------------------------------------------------------------+
    */

    function &GetKey($lockType){

        // Return the appropriate key
        return $this->Keys[$lockType];
    }

    /*
      +------------------------------------------------------------------+
      | This will set all the keys in the key array at once              |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function InsertKeys($private, $public){

        // Remove all keys
        $this->RemoveKey();

        // Reset all the locks
        $this->ResetLock();

        // Loop through all the keys
        foreach ($this->Keys as $KeyType => $Key){

            // If this is a factor key
            if (strstr($KeyType, 'factor')){

                // Set the key to the md5 hash of the keys array thus far
                $Key = md5(serialize($this->Keys));

            } else {

                // Set the key to the key we were passed
                $Key = $$KeyType;
            }

            // Insert the key we have in the end
            $this->InsertKey($Key, $KeyType);
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will set a $key for $lockType                               |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function InsertKey($key, $lockType){

        // If we have a key
        if (strlen($key) > 0){

            // Set the key
            $this->Keys[$lockType] = $key;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will turn a lock based on a keys contents                   |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function TurnKey($lockType = ''){

        // If we don't have a lock type
        if (!$lockType){

            // Loop through all the locks
            foreach ($this->Locks as $LockType => $Lock){

                // Call ourselves with this lock type
                $this->TurnKey($LockType);
            }

            // Don't pass this bit
            return;
        }

        // Get a reference to the desired key
        $Key =& $this->GetKey($lockType);

        // Loop through each character of the key
        for ($i = 0; $i < strlen($Key); $i++){

            // Work out how many steps to turn the lock
            $Steps = ord($Key[$i]) / ($i + 1);

            // If the decimal value of the current character is odd
            if (ord($Key[$i]) % 2 != 0){

                // Turn the lock left
                $this->TurnLock($lockType, $Steps, 'left');

            } else {

                // Turn the lock right
                $this->TurnLock($lockType, $Steps, 'right');
            }
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will clear a keys contents, all keys if no $lockType is set |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function RemoveKey($lockType = ''){

        // Loop through each of the keys
        foreach($this->Keys as $KeyName => $Key){

            // If this is our desired key or we don't have a desired key
            if ($lockType == $KeyName || strlen($lockType) == 0){

                // Reset this key
                $this->Keys[$KeyName] = '';
            }
        }
    }

    // Lock Methods

    /*
      +------------------------------------------------------------------+
      | This gets a reference to the character set a key manipulates     |
      |                                                                  |
      | @return reference                                                |
      +------------------------------------------------------------------+
    */

    function &GetLock($lockType){

        // Return a reference to the lock
        return $this->Locks[$lockType];
    }

    /*
      +------------------------------------------------------------------+
      | This will lock the data according to the current character index |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function Lock($data){

        // Reset the data
        $this->Data = '';

        // If we are supposed to be zipping
        if ($this->Zip == TRUE){

            // If we can't compress the data
            if (FALSE === ($data = @gzdeflate($data))){

                // Add the error incase the user wants to know why we failed
                $this->Error('There was a problem compressing the data');

                // Huston, we have a problem
                return FALSE;
            }
        }

        // If we can compress the character
        if (FALSE !== ($data = base64_encode($data))){

            // Loop through each character in the data
            for ($i = 0; $i < strlen($data); $i++){

                // Convert this character to its encrypted equivilent
                $data[$i] = $this->GetChar($data[$i], TRUE);
            }

            // Looks like we have ourselves some data
            $this->Data = $data;

            // And thats all folks
            return $this->Data;

        } else {

            // Add the error to let the user know why we failed
            $this->Error('There was a problem encoding the data');

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This unlocks the data according to the current character index   |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function Unlock($data){

        // Reset the data
        $this->Data = '';

        // Loop through each character in the data
        for ($i = 0; $i < strlen($data); $i++){

            // Convert this character to its decrypted equivilent
            $data[$i] = $this->GetChar($data[$i], FALSE);
        }

        // If we can base64 decode the data
        if (FALSE !== ($data = base64_decode($data))){

            // If we can decompress data
            if (FALSE !== ($data = @gzinflate($data))){

                // Looks like we have ourselves some data
                $this->Data = $data;

                // Thats all folks
                return $this->Data;

            } else {

                // Tell the user why we failed
                $this->Error('There was a problem decompressing the data');

                // Failure
                return FALSE;
            }

        } else {

            // Add the error ro the error stack
            $this->Error('There was a problem decoding the data');

            // Failure
            return FALSE;
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will turn a lock (character set) $steps steps in $direction |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function TurnLock($lockType, $steps = 5, $direction = 'right'){

        // Loop through the required number of steps
        for ($i = 0; $i < $steps; $i++){

            // Get a reference to the lock
            $Lock =& $this->GetLock($lockType);

            // If we are not going right, reverse the string
            if ($direction != 'right') $Lock = strrev($Lock);

            // Make a copy of the counter
            $c = $i;

            // If we are rotating a character passed the end of the character set
            if ($c >= strlen($Lock)){

                // While we still have too little characters to split
                while ($c >= strlen($Lock)){

                    // Minus the lock length from the counter
                    $c = $c - strlen($Lock);
                }
            }

            // Isolate the first character in the charset
            $Char = substr($Lock, 0, 1);
            $Lock = substr($Lock, 1);

            // If our split point exists
            if (strlen($Lock[$c]) > 0){

                // Split the string at the desired position
                $Chunks = explode($Lock[$c], $Lock);

                // If we have some chunks
                if (is_array($Chunks)){

                    // Then piece together the string
                    $Lock = $Chunks[0].$Lock[$c].$Char.$Chunks[1];
                }

            } else {

                // Put the lock back to the way it was
                $Lock = $Char.$Lock;
            }

            // If we are not going right, reverse the string back
            if ($direction != 'right') $Lock = strrev($Lock);
        }
    }

    /*
      +------------------------------------------------------------------+
      | This will generate the original charset and character index      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function ResetLock($lockType = ''){

        // Get the base 64 compatible character set
        $CharSet = $this->GetCharSet();

        // Loop through the keys we have
        foreach ($this->Keys as $LockType => $Key){

            // If we were supplied a lock type to reset
            if ($lockType){

                // If this is our lock
                if ($LockType == $lockType){

                    // Then reset the lock
                    $this->Locks[$LockType] = $CharSet;

                    // And we're done
                    return;
                }

            } else {

                // Reset this lock
                $this->Locks[$LockType] = $CharSet;
            }
        }
    }

    // Character Set Methods

    /*
      +------------------------------------------------------------------+
      | This will lookup the encrypted/decrypted version of a character  |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function GetChar($char, $encrypt = FALSE){

        // If we are not encrypting, flip the locks
        if (!$encrypt) $this->Locks = array_reverse($this->Locks);

        // Initate the lock counter
        $i = 0;

        // Loop through each lock
        foreach ($this->Locks as $LockType => $Lock){

            // If this is the first lock, set the initial position
            if ($i == 0){

                // Get the initial position
                $Position = strpos($Lock, $char);
            }

            // If the lock counter is odd, or this is the final iteration
            if ($i % 2 > 0){

                // If we are encrypting
                if ($encrypt){

                    // Swap position
                    $Position = strpos($Lock, $char);

                } else {

                    // Swap character
                    $char = $Lock[$Position];
                }

            } else {

                // If we are encrypting
                if ($encrypt){

                    // Swap character
                    $char = $Lock[$Position];

                } else {

                    // Swap position
                    $Position = strpos($Lock, $char);
                }
            }

            // Increment the lock counter
            $i++;
        }

        // If we are not encrypting, flip the locks
        if (!$encrypt) $this->Locks = array_reverse($this->Locks);

        // Return the character
        return $char;
    }

    /*
      +------------------------------------------------------------------+
      | This will generate and return a base 64 compatible charset       |
      |                                                                  |
      | @return string                                                   |
      +------------------------------------------------------------------+
    */

    function GetCharSet(){

        // These are forbidden characters that fall in the range of chars we iterate
        $ForbiddenChars = array_merge(range(44, 46), range(58, 64), range(91, 96));

        // Loop through the base64 compatible range of characters
        for ($i = 43; $i < 123; $i++){

            // If this is not a forbidden character
            if (!in_array($i, $ForbiddenChars)){

                // Then add this to the final character set
                $return .= chr($i);
            }
        }

        // Return the final character set
        return $return;
    }

    // Error Reporting Methods

    /*
      +------------------------------------------------------------------+
      | This will add an error message to the error message stack        |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Error($msg){

        // Add the error to the stack
        $this->Errors[] = $msg;
    }

    /*
      +------------------------------------------------------------------+
      | This will display the error messages specific to the current env |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function ShowErrors($returnVal = FALSE){

        // Loop through all the errors
        foreach ($this->Errors as $Error){

            // If we are being called from the web
            if (strlen($_SERVER['REQUEST_METHOD']) > 0){

                // Format the errors for the web
                $return .= '<strong>Error:</strong> '.$Error.'<br />';

            } else {

                // Format the error message for the command line
                $return .= '[-] '.$Error."\n";
            }
        }

        // Now that we are showing the errors, we can clear them too
        $this->Errors = array();

        // If we are supposed to the return the errors
        if ($returnVal){

            // Then return them we shall
            return $return;

        } else {

            // Output the errors directly
            echo $return;
        }
    }

    // Debug Methods

    /*
      +------------------------------------------------------------------+
      | This will output a message instantly for debugging purposes      |
      |                                                                  |
      | @return void                                                     |
      +------------------------------------------------------------------+
    */

    function Debug($msg){

        // Turn implicit output buffering on incase it is off
        ob_implicit_flush(1);

        // If we are being called from the web
        if (strlen($_SERVER['REQUEST_METHOD'])){

            // Then format the message for the web
            $msg = '<strong>Debug:</strong> '.$msg.'<br />';

        } else {

            // Format the message for a CLI
            $msg = '[i] '.$msg."\n";
        }

        // Output the message
        echo $msg;
    }
 }

?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products