<?php

@( (bool)FALSE === strpos( $_SERVER['REQUEST_URI'], basename( __FILE__ ) ) ) OR exit( '!! ACCESS DENIED !!' );
error_reporting( _E_VALUE );

/* vim: set expandtab tabstop=4 shiftwidth=4: */

// ***** BEGIN LICENSE BLOCK ( DO NOT REMOVE ) *****

// +----------------------------------------------------------------------+
// | Nested Page Project (NPP) For MPN 188_8                              |
// | -> Base Class                                                        |
// +----------------------------------------------------------------------+
// | VERSION: 0.1 Alpha                                                   |
// +----------------------------------------------------------------------+
// | LICENSE: GPL 2.0 (see docs/LICENSE_GPL)                              |
// |                                                                      |
// | This file is part of The Nested Page Project For MPN 188_8.          |
// |                                                                      |
// | The Nested Page Project For MPN 188_8 is free software; you can      |
// | redistribute it and/or modify it under the terms of the GNU          |
// | General Public License as published by the Free Software Foundation; |
// | either version 2 of the License, or (at your option) any             |
// | later version.                                                       |
// |                                                                      |
// | The Nested Page Project For MPN 188_8 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 General Public License for more details.        |
// |                                                                      |
// | You should have received a copy of the GNU General Public License    |
// | along with The Nested Page Project For MPN 188_8; if not, write to   |
// | the                                                                  |
// |                                                                      |
// | Free Software Foundation, Inc.                                       |
// | 59 Temple Place, Suite 330                                           |
// | Boston, MA 02111-1307  USA                                           |
// +----------------------------------------------------------------------+
// | AUTHOR(s):                                                           |
// |                                                                      |
// | The Original Code is The Nested Page Project For MPN 188_8.          |
// | The Initial Developer of the Original Code is Eric Haddix.           |
// |                                                                      |
// | Portions created by Eric Haddix or Kiril Threndor                    |
// | <support@mpn.illearth.net> are                                       |
// | Copyright (C) 2003 Eric Haddix.  All Rights Reserved.                |
// +----------------------------------------------------------------------+
// | CONTRIBUTOR(s):                                                      |
// |                                                                      |
// |                                                                      |
// +----------------------------------------------------------------------+
// | MODIFICATIONS:                                                       |
// |                                                                      |
// |                                                                      |
// +----------------------------------------------------------------------+
// | NOTES:                                                               |
// |   This IS alpha code, so code may or may not change at any time      |
// |   I recommend you don't spend alot of time working with this class   |
// |   unless you want to do it again.  This is WORK IN PROGRESS !!       |
// |   Complete Code comments and a readme will be completed for          |
// |   the first full release.                                            |
// |                                                                      |
// +----------------------------------------------------------------------+
// | Required Files:                                                      |
// |   -> core_Snoopy.class.php vs. 1.01a ( Modified For N_P_P )          |
// |      * Snoopy vs. 1.01 ( http://sourceforge.net/projects/snoopy/ )   |
// |   -> core_Sanitize.class.php                                         |
// |   -> core_Sanitize.param.php                                         |
// |   -> core_SSP_DefaultFormat.param.php                                |
// |   -> your custom child class(es) and supporting files                |
// +----------------------------------------------------------------------+
// | SUPPORT:                                                             |
// |   WEB:   http://myphpnuke.com/                                       |
// |   EMAIL: support@mpn.illearth.net                                    |
// +----------------------------------------------------------------------+

/**
 * MPN_188_8_Modules
 *
 * @package MPN_188_8_Modules
 * @subpackage Nested Page Project
 * @version $Id: core_NestedPageProject.class.php,v 1.3.2.6 2004/08/15 12:58:24 kirilt Exp $
 *
 * @author Kiril Threndor <support@mpn.illearth.net>
 * @copyright Copyright (C) 2003 Eric Haddix
 * @license http://www.gnu.org/licenses/gpl.html GPL 2.0
 * @support http://myphpnuke.com/
 * @todo commenting
 * @todo add code for NPP Partner
 * @todo get alpha 2 together
 *
 * @tutorial
 * @filesource
 */

// ***** END LICENSE BLOCK ( DO NOT REMOVE ) *****

class NestedPageProject
{
    var $npp_version           = '0.1 Alpha';

    // Debugging

    var $npp_debug             = FALSE;
    var $exit_when_debugging   = FALSE;
    var $npp_debug_link_ary    = FALSE;
    var $disable_child_verify  = FALSE;

    // Formatting Aids

    var $add_insert_comm       = FALSE;
	var	$add_pos_comm	       = FALSE;
	var	$add_pos_inc	       = 500;

    // General Variables

    var $class_root            = _DP_CLASS_PAR;
    var $san_param             = 'core_NestedPageProject.sparam.php';
    var $format_file           = 'core_NestedPageProject.fparam.php';
    var $snoopy_class          = 'core_Snoopy.class.php';
    var $sanitizer_class       = 'core_Sanitize.class.php';
    var $sanitizer_child       = 'subs/sanitizer/core_CheckInput.subclass.php';
    var $inc_format_arys       = FALSE;

    var $subclass_root         = NULL;
    var $subsan_param          = NULL;
    var $subformat_file        = NULL;
    var $rmt_site_id           = NULL;

    var $localize_links        = array();
    var $body_length           = 0;
    var $arg1_name             = 'req';
    var $arg2_name             = 'par';

    // N_P_N Partner

    var $npn_partner           = FALSE;
    var $npn_id                = NULL;

    // Embedded Objects

    var $snoopy                = NULL;
    var $npp_sanitize          = NULL;

    // Default Sanitizing

    var $allow_html            = TRUE;
    var $allow_imgs            = FALSE;
    var $censor                = TRUE;

    var $validate_links        = TRUE;
    var $localize_links        = array( 'a' );
    var $add_title_attr        = TRUE;

    var $sanitize_param        = array( 1, TRUE, NULL, NULL );

    // Formatting Arrays Defined In Child Class fparam File

    var $rmt_pre_scan          = array();
    var $rmt_post_scan         = array();
    var $rmt_fix_form_query    = array();
    var $rmt_fix_paths         = array();
    var $rmt_disp_format       = array();
    var $rmt_disp_split_format = array();
    var $rmt_form_ids          = array();
    var $rmt_form_vars         = array();
    var $rmt_form_num          = 0;

    // Forms

    var $allow_forms           = FALSE;
    var $snoopy_reset          = FALSE;
    var $form_name             = array( 'name' => 'npp_formid' );

    var $req_form              = array(   'submit'  => FALSE
                                        , 'req_uri' => NULL
                                        , 'data'    => array()
                                        , 'files'   => array()
                                        , 'method'  => 'post'
                                      );

    // Internal Variables

    var $local_root            = _MPN_ROOT_URI;
    var $local_uri             = '';
    var $link_css              = 5;
    var $npp_div_id            = 'npp_body';
    var $local_body            = '';
    var $rmt_body              = '';
    var $rmt_parent            = NULL;
    var $rmt_request           = NULL;
    var $open_new              = TRUE;
    var $poss_domains          = array();


    // Subclass Related Variable Defaults

    // Remote Related Variables

    var $rmt_root              = NULL;
    var $rmt_page              = NULL;
    var $rmt_root_uri          = NULL;
    var $rmt_root_dname        = NULL;
    var $rmt_schemes           = array( 'http', 'https', 'ftp' );
    var $rmt_root_pdnames      = array( '', 'www' );
    var $rmt_root_sdnames      = array();
    var $rmt_tlds              = array( array( 'com', 'net', 'org', 'edu', 'int', 'aero', 'biz', 'coop', 'info', 'museum', 'name', 'pro' ) );
    var $rmt_cctlds            = array();
    var $rmt_ports             = array();
    var $rmt_user              = NULL;
    var $rmt_pass              = NULL;

    // N_P_N Remote Share Partner Defaults

    var $rmt_npn_partner       = FALSE;
    var $rmt_npn_id            = NULL;

    // Localization Options

    var $rmt_allow_query       = TRUE;
    var $rmt_allow_subs        = TRUE;
    var $rmt_allow_trav        = TRUE;
    var $rmt_trav_depth        = NULL;
    var $rmt_single_page       = TRUE;

/**
 * Parent Class Initializer
 *
 * @return void
 */

function initializeParent()
{
    // Verify Sub-Class Variables && Initilize Parent Internal Variables

    if ( ! $this -> disable_child_verify && (bool)TRUE !== ( $status = $this -> verifyChildVars() ) )
    {
        return $this -> returnError( $status );
        exit;
    }

    // Set Paths And Load Required Files

    // Child Class Sanitizer Parameters

    if ( ! empty ( $this -> subclass_root ) && ! empty( $this -> subsan_param ) )
    {
        $this -> san_param = $this -> subclass_root . $this -> subsan_param;
    }

    // Child Class Formatting Parameters

    if ( $this -> inc_format_arys )
    {
        if ( ! empty ( $this -> subclass_root ) && ! empty( $this -> subformat_file ) )
        {
            $this -> format_file = $this -> subclass_root . $this -> subformat_file;

            //$this -> npDump( 'initializeParent', 'Format File Is', $this -> format_file );

            if ( ! @include( $this -> format_file ) )
            {
                return $this -> returnError( 'include_open', $this -> format_file );
            }

            if ( ! empty( $rmt_fix_paths ) )      { $this -> rmt_fix_paths = $rmt_fix_paths; }

            if ( ! empty( $rmt_form_num ) )       { $this -> rmt_form_num = $rmt_form_num; }
            if ( ! empty( $rmt_form_ids ) )       { $this -> rmt_form_ids = $rmt_form_ids; }
            if ( ! empty( $rmt_form_vars ) )      { $this -> rmt_form_vars = $rmt_form_vars; }
            if ( ! empty( $rmt_fix_form_query ) ) { $this -> rmt_fix_form_query = $rmt_fix_form_query; }

            if ( ! empty( $rmt_pre_scan ) )       { $this -> rmt_pre_scan = $rmt_pre_scan; }
            if ( ! empty( $rmt_post_scan ) )      { $this -> rmt_post_scan = $rmt_post_scan; }
            if ( ! empty( $rmt_disp_format ) )    { $this -> rmt_disp_format = $rmt_disp_format; }
        }
    }

    // Make sure the required classes are loaded if not already.
    // Files are assumed to be located in the same directory as this file.
    // Sub-directories in the class root are fine, but make sure the path
    // is defined correctly

    require_once $this -> class_root . $this -> snoopy_class;

    // Instantiate And Initialize Snoopy

    $this -> snoopy = new Snoopy;

    if ( empty( $this -> snoopy ) || ! is_object( $this -> snoopy ) )
    {
        return $this -> returnError( 'class_fail' );
    }

    $this -> snoopy -> expandlinks = (bool)FALSE;

    require_once $this -> class_root . $this -> sanitizer_class;
    require_once $this -> class_root . $this -> sanitizer_child;

    // Instantiate And Initialize Sanitizer

    $this -> npp_sanitize = new CheckRequest(   $this -> allow_html
                                              , $this -> san_param
                                              , NULL
                                              , $this -> censor
                                            );

    if ( empty( $this -> npp_sanitize ) || ! is_object( $this -> npp_sanitize ) )
    {
        return $this -> returnError( 'class_fail' );
    }

    $this -> npp_sanitize -> add_attrib     = (bool)TRUE;
    $this -> npp_sanitize -> track_links    = (bool)TRUE;
    $this -> npp_sanitize -> validate_links = $this -> validate_links;
    $this -> npp_sanitize -> add_pos_comm   = $this -> add_pos_comm;
    $this -> npp_sanitize -> add_pos_inc    = $this -> add_pos_inc;

    if ( ! $this -> allow_imgs )
    {
        array_push( $this -> npp_sanitize -> rm_tags_with_content, 'img' );

        if ( $this -> npp_sanitize -> rmtags )
        {
            unset( $this -> npp_sanitize -> taglist['img'] );
        }
    }

    // INITIALIZING ROOTS

    // Local

    $this -> local_uri = $this -> local_root . substr( strrchr( $_SERVER['SCRIPT_NAME'], '/' ), 1 );

    //$this -> npDump( 'initializeParent', 'Local URI Is', $this -> local_root );

    // Remote

    if ( ! empty( $this -> rmt_page ) )
    {
        $this -> rmt_root_uri = $this -> rmt_root . $this -> rmt_page;
    }
    else
    {
        $this -> rmt_root_uri = $this -> rmt_root;
    }

    // Build An Array Of Possible Domain Names

    $multiary = array(   $this -> rmt_cctlds
                       , $this -> rmt_tlds
                       , array( $this -> rmt_root_dname )
                       , array_merge( $this -> rmt_root_pdnames, $this -> rmt_root_sdnames )
                     );

    $this -> buildDomainArray( $multiary );

    unset( $multiary );

    //$this -> npDump( 'initializeParent', 'Possible Domains Are', $this -> poss_domains );

    // Decode Remote Parent If It Exists

    if ( isset( $_REQUEST[ $this -> arg2_name ] ) && $_REQUEST[ $this -> arg2_name ] != '' )
    {
        $this -> rmt_parent = base64_decode( $_REQUEST[ $this -> arg2_name ] );

        $par_check = $this -> buildRemoteURI( $this -> rmt_parent, TRUE );

        if ( (bool)TRUE !== $par_check )
        {
            if ( is_string( $par_check ) )
            {
                return $this -> returnError( $par_check, $this -> rmt_parent );
            }
            else
            {
                $this -> rmt_parent = $this -> rmt_root_uri;
            }
        }
    }
    else
    {
        $this -> rmt_parent = $this -> rmt_root_uri;
    }

    //$this -> npDump( 'initializeParent', 'Remote Parent Is Set At', $this -> rmt_parent );

    // Decode Requested Remote URI

    if ( isset( $_REQUEST[ $this -> arg1_name ] ) )
    {
        $this -> rmt_request = base64_decode( $_REQUEST[ $this -> arg1_name ] );

        //$this -> npDump( 'initializeParent', 'Incoming Request URI IS', $this -> rmt_request );
    }
    else
    {
        $this -> rmt_request = $this -> rmt_parent;
    }

    // Check For Forms Allowance

    if (    $this -> allow_forms
         && ( isset( $this -> rmt_form_num ) && $this -> rmt_form_num > 0 )
         && ( is_array( $this -> rmt_form_ids ) && sizeof( $this -> rmt_form_ids ) === $this -> rmt_form_num )
       )
    {
        $this -> npp_sanitize -> track_forms = (bool)TRUE;
        $this -> npp_sanitize -> form_num = $this -> rmt_form_num;

        //$this -> npDump( 'initializeParent', 'Tracking Forms. Expected Form Count', $this -> rmt_form_num );

        if ( $this -> rmt_form_num > 1 )
        {
            foreach ( $this -> rmt_form_ids AS $key => $v )
            {
                $this -> rmt_form_ids[ $key ] = array_merge( $this -> form_name, $this -> rmt_form_ids[ $key ] );
            }
        }
        else
        {
            $this -> rmt_form_ids[1] = array_merge( $this -> form_name, $this -> rmt_form_ids[1] );
        }

        $this -> npp_sanitize -> form_ids = $this -> rmt_form_ids;
    }
    else
    {
        //$this -> npDump( 'initializeParent', 'Form Tracking DISABLED. Forms will be stripped from document' );

        $this -> npp_sanitize -> track_forms = (bool)FALSE;
        $merge = array( 'form' );
        $this -> npp_sanitize -> rm_tags_with_content = array_merge( $this -> npp_sanitize -> rm_tags_with_content, $merge );
    }

    return (bool)TRUE;

} // End Parent Initializer

/**
 * This Is The N_P_P Class Control Center
 *
 * This Is The Only Parent Class Method That Needs
 * To Be Called By The Child Class Directly In Most Cases
 *
 * @return string ( Remote Body Ready For Display Or Error Message )
 */

function nestRemotePage()
{
    // Error Handling

    $status = array();
    $error = NULL;

    // Validate Requested Remote URI

    $status[] = $this -> validateRequestURI();

    // Fetch The Remote Page

    $status[] = $this -> getRemotePage();
    $this -> body_length = strlen( $this -> local_body );

    // Apply Any Pre-Sanitizer Replacements If Required

    $status[] = $this -> applyFormatArray( 'rmt_pre_scan' );
    $this -> body_length = strlen( $this -> local_body );

    // Sanitize And Localize The Remote Content

    $status[] = $this -> localizeRemoteContent();
    $this -> body_length = strlen( $this -> local_body );

    // Apply Any Post Sanitizer Scan Replacements

    $status[] = $this -> applyFormatArray( 'rmt_post_scan' );
    $this -> body_length = strlen( $this -> local_body );

    // Apply Final Body Formatting And Content Additions

    $status[] = $this -> formatBody();
    $this -> body_length = strlen( $this -> local_body );

    // The following method must be called
    // under the N_P_P copyright restrictions
    // DO NOT REMOVE

    $status[] = $this -> wrapContent();
    $this -> local_body = trim( $this -> local_body );
    $this -> body_length = strlen( $this -> local_body );

    // Process Error Status

    foreach( $status AS $v )
    {
        if ( (bool)TRUE !== $v )
        {
            $error .= $v . '<br /><br />';
        }
    }

    // If Debugging, Dump The Local Body And Status

    if ( $this -> npp_debug )
    {
        //$this -> npDump( 'sanitizeRemoteContent', 'SUCCESS. Dumping Final Body', $this -> local_body );

        echo $this -> local_body;

        if ( $this -> exit_when_debugging ) { exit; }
    }

    // Return Content Or Error To Child Class Method

    if ( ! empty( $error ) )
    {
        return '<div class="errmsg">' . $error . '</div>';
    }

    return $this -> local_body;

} // End Method nestRemotePage


// ############# FETCH AND LOCALIZING METHODS ############# //


/**
 * Verify Incoming Request URI and Parent URI
 *
 * @return bool ( true on success, error on fail )
 */

function validateRequestURI()
{
    //$this -> npDump( 'validateRequestURI', 'Remote Request Is Currently Set At', $this -> rmt_request );

    // Check If The Request Is The Root Or The Parent, Pass If It Is

    if (    $this -> rmt_request === $this -> rmt_root_uri
         || $this -> rmt_request === $this -> rmt_parent
       )
    {
        //$this -> npDump( 'validateRequestURI', 'Request URI Validated.', $this -> rmt_request );

        return (bool)TRUE;
    }

    // Request URI Validation

    $req_check = $this -> buildRemoteURI( $this -> rmt_request, TRUE );

    // Check Status Of URI Validation

    if ( (bool)TRUE !== $req_check )
    {
        if ( is_string( $req_check ) )
        {
            return $this -> returnError( $req_check, $this -> rmt_request );
        }
        else
        {
            if ( $this -> npp_debug ) { exit( '<br />Exit Before Redirect' ); }

            $this -> redirectRequest( $this -> rmt_request );
        }
    }

    //$this -> npDump( 'validateRequestURI', 'Request URI Validated.', $this -> rmt_request );

    return (bool)TRUE;

} // End Method verifyRequestURI

/**
 * Fetch Remote Page
 *
 * @return mixed ( bool on success, error on fail )
 */

function getRemotePage()
{
    //$this -> npDump( 'getRemotePage', 'Fetching Remote Page', $this -> rmt_request );

    $fetch = (bool)FALSE;

    if ( $this -> allow_forms )
    {
        $chk_submit = $this -> prepFormRequest();
    }

    if ( ! $chk_submit )
    {
        //$this -> npDump( 'getRemotePage', 'Processing NORMAL GET Request', $this -> rmt_request );

        if ( $this -> npn_partner )
        {
            $this -> rmt_request .= '&#038;npnid=' . md5( $this -> npn_id );
        }

        $fetch = $this -> snoopy -> fetch( $this -> rmt_request, $this -> snoopy_reset );
    }
    else
    {
        if ( $this -> npn_partner && ! empty( $this -> npn_id ) )
        {
            $this -> req_form['req_uri'] .= '&#038;npnid=' . md5( $this -> npn_id );
        }

        if ( $this -> req_form['submit'] )
        {
            //$this -> npDump( 'getRemotePage', 'Processing FORM POST Request', $this -> req_form );

            $fetch = $this -> snoopy -> submit(   $this -> req_form['req_uri']
                                                , $this -> req_form['data']
                                                , $this -> req_form['files']
                                                , $this -> snoopy_reset
                                              );

            if ( ! $fetch )
            {
                //$this -> npDump( 'getRemotePage', 'Form Processing Failure, Fetching Parent', $this -> snoopy -> error );

                $fetch = $this -> snoopy -> fetch( $this -> rmt_parent, TRUE );
            }
        }
        else
        {
            //$this -> npDump( 'getRemotePage', 'Processing FORM GET Request', $this -> req_form['req_uri'] );

            $fetch = $this -> snoopy -> fetch( $this -> req_form['req_uri'], $this -> snoopy_reset );
        }
    }

    /**
     * Check Result Of Fetch Attempt.
     * If False, Return Error Message
     * If True, Set The Body Variables
     */

    if ( ! $fetch )
    {
        //$this -> npDump( 'getRemotePage', 'Fetch Get Request Failed', $this -> snoopy -> error );

        return $this -> returnError( 'remote_open' );
    }
    else
    {
        $this -> rmt_body = $this -> snoopy -> results;
        $this -> local_body  = $this -> rmt_body;
    }

    if ( $this -> rmt_npn_partner && ! empty( $this -> rmt_npn_id ) )
    {
        $this -> processNPNShare();
    }

    //$this -> npDump( 'getRemotePage', 'Fetch Success, Returning True' );

    return (bool)TRUE;

} // End Method

function processNPNShare()
{
    return returnError( 'not_avail' );
}

/**
 * Sanitize And Localize Remote Content
 *
 * @return mixed ( bool on success, error on fail )
 */

function localizeRemoteContent()
{
    //$this -> npDump( 'localizeRemoteContent', 'Localizing Remote Content. Returned Remote Body Is:', $this -> rmt_body );

    $key             = 0;
    $orig_links      = NULL;
    $local_links     = array();
    $link_qualifiers = array( '&#063;', '&#061;', '&#038;' );
    $gen_qualifiers  = array( '?', '=', '&' );

    // Run Remote Content Through Initial Sanitizing Scan

    $this -> sanitizeRemoteContent( $this -> local_body );

    $orig_links = $this -> npp_sanitize -> valid_links;

    //$this -> npDump( 'localizeRemoteContent', 'Sanitizer Returned The Following Links', $orig_links );

    if ( ! $this -> npp_debug_link_ary )
    {
        $parent_uri = base64_encode( $this -> rmt_request );
    }
    else
    {
        $parent_uri = $this -> rmt_request;
        $dubug_ary = array( 'orig' => array(), 'repl' => array() );
    }

    // Replace Remote Links With Localized Link If Not A Single Page Nest

    if ( ! $this -> rmt_single_page && ! empty( $orig_links ) )
    {
        foreach( $orig_links AS $tag => $linksary )
        {
            if ( empty( $linksary ) || ! in_array( $tag, $this -> localize_links ) )
            {
                //$this -> npDump( 'localizeRemoteContent', 'No Links Found, Or Skipping Localizing Links of tagtype', $tag );

                continue;
            }

            $qual = ( $tag == 'a' ) ? ( $link_qualifiers ) : ( $gen_qualifiers );

            foreach( $linksary AS $attname => $attvalues )
            {
                $key = 0;

                foreach( $attvalues AS $link )
                {
                    $key++;
                    $title = '';

                    $remote_links[ $key ] = $attname . '=' . $link;

                    if ( $this -> npp_debug_link_ary )
                    {
                        $dubug_ary['orig'][] = $remote_links[ $key ];
                    }

                    $link = $this -> npp_sanitize -> stripQuotes( $link );

                    if ( $this -> add_title_attr && $tag == 'a' )
                    {
                        $title = ' title="' . $link . '"';
                    }

                    if ( ! $this -> buildRemoteURI( $link ) )
                    {
                        //$this -> npDump( 'localizeRemoteContent', 'Link Failed URI Build. Adding Attr Target Is' . $this -> open_new, $link );

                        if ( ! $this -> open_new )
                        {
                            unset( $remote_links[ $key ] );
                            continue;
                        }

                        $local_links[ $key ] =  $attname
                                               . '='
                                               . '"'
                                               . $link
                                               . '"'
                                               . ' '
                                               . 'target="_blank"'
                                               . $title;

                    }
                    else
                    {
                        $local_links[ $key ] =  $attname
                                               .'='
                                               . '"'
                                               . $this -> local_uri
                                               . $qual[0]
                                               . 'enpp'
                                               . $qual[1]
                                               . $this -> rmt_site_id
                                               . $qual[2]
                                               . $this -> arg1_name
                                               . $qual[1]
                                               . $link
                                               . $qual[2]
                                               . $this -> arg2_name
                                               . $qual[1]
                                               . $parent_uri
                                               . '"'
                                               . $title;
                    }

                    if ( $this -> npp_debug_link_ary )
                    {
                        $dubug_ary['repl'][] = $local_links[ $key ];
                    }

                } // End Nested foreach
            } // End Nested foreach
        } // End Link Re-Build foreach

        if ( ! empty( $remote_links ) )
        {
            $this -> local_body = str_replace(   $remote_links
                                               , $local_links
                                               , $this -> local_body
                                             );
        }

        if ( $this -> npp_debug_link_ary )
        {
            //$this -> npDump( 'localizeRemoteContent', 'Link Replacement Complete. Link Original and Replacement Array Follows', $dubug_ary );
        }
        else
        {
            //$this -> npDump( 'localizeRemoteContent', 'Link Replacement Complete. New Body Of Content', $this -> local_body );
        }

        unset( $remote_links, $local_links );

    } // End Link Replacements

    // Set The New Body Length In The Event We Need To Do Some Additional Replacements

    $this -> body_length = strlen( $this -> local_body );

    if ( $this -> body_length == 0 )
    {
        //$this -> npDump( 'localizeRemoteContent', 'Document Body Is Empty, Returning Error', $this -> rmt_body );

        return $this -> returnError( 'no_content' );
    }

    return (bool)TRUE;

} // End Method

/**
 * Run Remote Content Through The Sanitizer
 *
 * @param string ( &$body      -> Body of text to process )
 * @param array  ( $sanity     -> Optional array of settings for the sanitizer )
 * @param bool   ( $update_pos -> Optional bool switch used to sanitizie the body
 *                                of content primarily just for updating position
 *                                comments )
 *
 * @return mixed ( bool on success, error on fail )
 */

function sanitizeRemoteContent( &$body, $sanity = array(), $update_pos = FALSE )
{
    if ( $update_pos )
    {
        $sanity = array( 5, FALSE, NULL, NULL );
    }

    if ( empty( $sanity ) ) { $sanity = $this -> sanitize_param; }

    //$this -> npDump( 'sanitizeRemoteContent', 'Sainitizing Remote Content With Parameters', $sanity );

    // REF: sanitize( $content, $type, $auto_close, $strip, $tag_list, $legacy

    $body = trim( $this -> npp_sanitize -> sanitize( $body, $sanity[0], $sanity[1], $sanity[2], $sanity[3] ) );

    return (bool)TRUE;

} // End Method

/**
 * Prepare A Form Submission For Sending To Remote Site
 *
 * Additionally validate the local form against the remote sites copy
 *
 * @return mixed ( bool on success, error on fail )
 */

function prepFormRequest()
{
    $cnt = 0;
    $_form_name = NULL;
    $keychk = array_keys( $_REQUEST );

    //$this -> npDump( 'prepFormRequest', 'Preparing Form Request ' . $this -> form_name['name'] . '. $_REQUEST Keys Are:', $keychk );

    // Check Current $_REQUEST Array Keys For A Form ID Match

    foreach( $keychk AS $v )
    {
        if ( (bool)FALSE !== strpos( $v, $this -> form_name['name'] ) )
        {
            $form_request = (bool)TRUE;
            $_form_name   = $_REQUEST[ $v ];
            break;
        }
    }

    // If Form Support Is Disabled Or The Remote Form Is Not Valid, Disable And Return

    if ( ! $this -> allow_forms || ( empty( $_form_name ) && ! isset( $this -> rmt_form_vars[ $_form_name ] ) ) )
    {
        //$this -> npDump(  'prepFormRequest', 'No Form Submission Detected, Forms Are Disabled ( ' . $this -> allow_forms . ' ), Child Class Array Check Failed, Or Invalid Form Request Detected.  Disabling Form Support', array( 'form_name' => $_form_name ) );

        $this -> allow_forms = (bool)FALSE;
        return (bool)FALSE;
    }

    // Determine Parent Page URI To Verify Form Submission Against

    if ( empty( $this -> rmt_parent ) && $this -> rmt_request === $this -> rmt_root_uri )
    {
        $getparent = $this -> rmt_root_uri;
    }
    else if ( ! empty( $this -> rmt_parent ) )
    {
        $getparent = $this -> rmt_parent;
    }
    else
    {
        //$this -> npDump( 'prepFormRequest', 'Unable To Determine Remote Parent URI', $this -> rmt_parent );

        $this -> allow_forms = (bool)FALSE;
        return (bool)FALSE;
    }

    // Fetching Remote Forms From Parent

    //$this -> npDump( 'prepFormRequest', 'Fetching Parent Forms' , $this -> rmt_parent );

    $fetch_forms = $this -> snoopy -> fetchform( $getparent );

    if ( ! $fetch_forms )
    {
         //$this -> npDump( 'prepFormRequest', 'Unable To Fetch Forms From Parent', $this -> snoopy -> error );

         return $this -> returnError( 'remote_open' );
    }

    $remote_forms = $this -> snoopy -> results;
    $this -> snoopy_reset = (bool)TRUE;

    if ( $remote_forms != '' )
    {
        $this -> sanitizeRemoteContent( $remote_forms, array( 4, FALSE, NULL, NULL ) );
    }

    /**
     * If the form variable array is empty, or the posting form name is not
     * in the parents form_array. If we can't track the forms then
     * it's an invalid from submission, or there are no forms present in the
     * parent source. Set Allow Forms To False And Return
     */

    if (    empty( $this -> npp_sanitize -> form_variables )
         || ! isset( $this -> npp_sanitize -> form_variables[ $_form_name ] )
       )
    {
        //$this -> npDump( 'prepFormRequest', 'Cannot Determine Requesting Form Name', $this -> npp_sanitize -> form_variables );

        $this -> allow_forms = (bool)FALSE;
        return (bool)FALSE;
    }

    /**
     * If We Got Here, this means the sanitizer has built an array of
     * form variables from the parent page.  Build the remote request
     * based on this array and the current local $_REQUEST variables.
     */

    $this -> req_form['method'] = $this -> npp_sanitize -> form_variables[ $_form_name ]['form']['method'];

    $this -> snoopy -> _submit_method = $this -> req_form['method'];

    $action_uri = $this -> npp_sanitize -> form_variables[ $_form_name ]['form']['action'];

    $chk_request = $this -> buildRemoteURI( $action_uri, TRUE );

    if (    (bool)FALSE === $chk_request
         || is_string( $chk_request )
         || $this -> rmt_request != $action_uri
       )
    {
        //$this -> npDump( 'prepFormRequest', 'Form Action Verification Failed', $this -> npp_sanitize -> form_variables );

        return $this -> returnError( 'invalid_request' );
    }

    /**
     * Now We Set The Form Variable Array That Will
     * Be Passed To Snoopy For Fetching The Remote Page
     */

    $this -> req_form['req_uri'] = $this -> rmt_request;

    foreach( $this -> rmt_form_vars[ $_form_name ]['request'] AS $v )
    {
        if ( isset( $_REQUEST[ $v ] ) && $this -> npp_sanitize -> searchMultiArray( $v,  $this -> npp_sanitize -> form_variables[ $_form_name ] ) )
        {
            $cnt++;

            if ( $this -> req_form['method'] == 'post' )
            {
                $this -> req_form['data'][ $v ] = $_REQUEST[ $v ];
            }
            else
            {
                $qualifier = ( $cnt == 1 ) ? ( '?' ) : ( '&' );

                $this -> req_form['req_uri'] .= $qualifier . $v . '=' . $_REQUEST[ $v ];
            }
        }
    }

    // Adjust The Query If Necessary

    $this -> adjustFormQuery( $this -> req_form['req_uri'], $this -> rmt_form_vars[ $_form_name ]['type'] );

    // Set The Submit Method To Determine Which Snoopy Method To Use

    if ( $this -> req_form['method'] == 'post' )
    {
        $this -> req_form['submit'] = (bool)TRUE;
    }

    //$this -> npDump( 'prepFormRequest', 'Form Submission Verified', $this -> req_form );

    return (bool)TRUE;

} // End Method prepFormRequest

/**
 * Verify And Validate Remote URI / Link
 *
 * @param string ( &$uri       -> Reference to URI/URL being processed )
 * @param bool   ( $request    -> TRUE = Requested URI, FALSE = Link Within Body Of Text )
 * @param bool   ( $recurse    -> Failsafe infinite loop break if method is recursing )
 *
 * @return mixed ( bool on success, error on fail )
 */

function buildRemoteURI( &$uri, $request = FALSE, $recurse = FALSE )
{
    //$this -> npDump( 'buildRemoteURI', 'Processing URI', array( $request, $uri ) );

    $uri_parts  = parse_url( $uri );
    $root_parts = parse_url( $this -> rmt_root_uri );

    $uri_parts  = $this -> npp_sanitize -> stripQuotes( $uri_parts );
    $root_parts = $this -> npp_sanitize -> stripQuotes( $root_parts );

    /**
     * First lets check for a properly formed link or request
     * ( eg. A URI Without A Path Component Is Invalid and a return
     * value of FALSE from the parse call also indicates an invalid URI
     * due to a hack attempt or just a mangled URI
     *
     * Two possible courses of action here:
     *
     *   1) Parse returns false -> set URI to rmt_root and return
     *   2) URI without a path component -> fix and recurse
     *
     * The bool $recurse switch is to prevent any infinite loops
     * which should never happen, but it doesn't hurt to be safe
     */

    if ( ! $recurse )
    {
        if ( (bool)FALSE === $uri_parts )
        {
            $uri = $this -> rmt_root_uri;

            if ( ! $request )
            {
                $uri = base64_encode( $uri );
                return (bool)TRUE;
            }
            else
            {
                //$this -> npDump( 'buildRemoteURI', 'Invalid request syntax. Returning Error', $uri_parts );

                return 'invalid_request_syntax';
            }
        }

        if ( empty( $uri_parts['path'] ) )
        {
            if ( substr( $uri, -1 ) !== '/' )
            {
                $uri .= '/';

                //$this -> npDump( 'buildRemoteURI', 'Invalid Link, No Trailing Slash. Adding Slash And Rrecursing. NEW URI = ' . $uri, $uri_parts );

                $this -> buildRemoteURI( $uri, $request, TRUE );
            }
        }
    }

    $recurse = (bool)FALSE;

    // Set URI Part Checks For Following Checks

    $chk_scheme   = ( ! empty( $uri_parts['scheme'] ) );
    $chk_host     = ( ! empty( $uri_parts['host']   ) );
    $chk_port     = ( ! empty( $uri_parts['port']   ) );
    $chk_query    = ( ! empty( $uri_parts['query']  ) );

    /**
     * Initial Query & Path Checks
     *
     * Double checking empty path here just in case it slipped
     * through the first check.  If it did, we did what we could.
     * If it's a request, return error, else just return the link.
     *
     * return
     *  1) Request -> error
     *  2) link    -> TRUE = localize link
     */

    //$this -> npDump( 'buildRemoteURI', 'Checking For Empty Path And If Query Is Present And Allowed', $uri_parts );

    if ( empty( $uri_parts['path'] ) || ( $chk_query && ! $this -> rmt_allow_query ) )
    {
        if ( $request )
        {
            //$this -> npDump( 'buildRemoteURI', 'Invalid request syntax. Returning Error', $uri_parts );

            return 'invalid_request_syntax';
        }
        else
        {
            //$this -> npDump( 'buildRemoteURI', 'Invalid Link Syntax. Returning Link Unchanged', $uri_parts . ' chk_query = ' . $chk_query . ' rmt_allow_query = ' . $this -> rmt_allow_query );

            return (bool)TRUE;
        }
    }

    /**
     * Host And Scheme Checks For Outgoing Remote Page Requests
     * If Scheme is empty then it is assumed host is empty too and we
     * are dealing with a relative link that belongs to the remote host
     *
     * @return bool -> FALSE on Fail
     */

    if ( $chk_scheme )
    {
        // Host Checks

        $host_check = (bool)TRUE;
        $host_parts = explode( '.', $uri_parts['host'] );
        $short_dom  = sizeof( $host_parts ) === 2;
        $root       = ( $short_dom || ( ! $short_dom && in_array( $host_parts[0], $this -> rmt_root_pdnames ) ) );

        $subdom_name  = ( ! $short_dom )
                      ? ( $host_parts[0] )
                      : ( NULL );

        // Check Domain And Sub-Domain Access

        if ( ! is_array( $this -> poss_domains ) || ! in_array( $uri_parts['host'], $this -> poss_domains ) )
        {
            //$this -> npDump( 'buildRemoteURI', 'Invalid Host Name, Or Host Does Not Belong To Remote Host Domain. Returning FALSE', array( $uri_parts, $this -> poss_domains ) );

            return (bool)FALSE;
        }

        // Check Sub-Domain Access

        if ( ! $this -> rmt_allow_subs && ! $root && ! $short_dom && ! in_array( $host_parts[0], $this -> rmt_root_pdnames ) )
        {
            //$this -> npDump( 'buildRemoteURI', 'Restricted Sub-Domain. Returning FALSE', $uri_parts );

            return (bool)FALSE;
        }

        /**
         * If we got this far, then we have a link
         * or request that belongs to the remote domain
         */

        // Scheme Check

        //$this -> npDump( 'buildRemoteURI', 'Checking Scheme', $uri_parts['scheme'] );

        if ( ! in_array( $uri_parts['scheme'], $this -> rmt_schemes ) )
        {
            //$this -> npDump( 'buildRemoteURI', 'Invalid Scheme Found. Returning FALSE', $uri_parts );

            return (bool)FALSE;
        }

        // Port Check

        //$this -> npDump( 'buildRemoteURI', 'Checking Port' );

        if ( $chk_port && ! in_array( $uri_parts['port'], $this -> rmt_ports ) )
        {
            //$this -> npDump( 'buildRemoteURI', 'Invalid Port Found. Returning FALSE', $uri_parts );

            return (bool)FALSE;
        }
    }

    /**
     * Path Checks
     *
     * First -> Rebuild the path if required and
     * check if there is a file name present
     *
     * Method verifyPath returns bool for page check,
     * path is passed by reference.
     */

    //$this -> npDump( 'buildRemoteURI', 'Checking Path', $uri_parts['path'] );

    $chk_page   = $this -> verifyPath( $uri_parts['path'] );

    $path_parts = explode( '/', $uri_parts['path'] );
    $path_depth = sizeof( $path_parts );
    $path_len   = strlen( $uri_parts['path'] );


    /**
     * Check Directory Traversing And Directory Access
     *
     * Setting Some Variables For Processing Path
     */

    $poss_page     = substr( strrchr( $uri_parts['path'], '/' ), 1 );
    $poss_page_len = strlen( $poss_page );
    $req_page_name = (    $chk_page
                       && ( $poss_page_len > 0 )
                       && (bool)FALSE !== strpos( $poss_page, '.' )
                     )
                   ? ( trim( $poss_page ) )
                   : ( (bool)FALSE );

    $path_2        = ( is_string( $req_page_name ) )
                   ? ( substr( $uri_parts['path'], 0, ( $path_len - $poss_page_len ) ) )
                   : ( (bool)FALSE );

    $path_2_len    = ( is_string( $path_2 ) )
                   ? ( strlen( $path_2 ) )
                   : ( 0 );

    $path_parts_2  = ( $path_2_len > 0 )
                   ? ( explode( '/', $uri_parts['path'] ) )
                   : ( 0 );

    $path_depth_2  = ( is_array( $path_parts_2 ) )
                   ? ( sizeof( $path_parts ) )
                   : ( 0 );

    /**
     * Check Sub Directory Access
     *
     * Condition 1: Path Length > 1 && A File Name Was Not Found
     * Condition 2: Page Name Length > 1 && A Path Preceeds It That Is Not The Root
     */

    if (    ( $path_len > 1 && (bool)FALSE === $req_page_name )
         || ( $poss_page_len > 1 && ( (bool)FALSE !== $path_2 && $path_2_len > 1 ) )
       )
    {
        // We Have A Sub-Directory Request

        if ( ! $this -> rmt_allow_trav )
        {
            //$this -> npDump( 'buildRemoteURI', 'Restricted Sub-Directory. Setting Link To Root. If Request, Returning FALSE', $uri_parts );

            $uri_parts['path'] = '/';

            if ( $request ) { return (bool)FALSE; }
        }
        else
        {
            if ( ! empty( $this -> rmt_trav_depth ) )
            {
                $chk_depth = ( (bool)FALSE !== $path_2 ) ? ( $path_depth_2 ) : ( $path_depth );

                if ( $chk_depth > $this -> rmt_trav_depth )
                {
                    //$this -> npDump( 'buildRemoteURI', 'Maximum Directory Traversing Depth Violation. Returning FALSE', array( 'allowed' => $this -> rmt_trav_depth, 'attempt' => $chk_depth ) );

                    return (bool)FALSE;
                }
            }
        }
    }

    /**
     * Made It To This Point So We Have The Following:
     *
     * 1) A Valid Request Or Link ( absolute or relative )
     * 2) Fixed Path Component Ready For Link Re-assembling
     *
     * Next we check to see if the uri might need repairing
     *
     * There are three repair options here:
     *
     *  1) Repair Relative URI Based On Path
     *  2) Repair based on a unique string in the query
     *  3) Repair based on requested file name
     */

    if ( ! $request && ! empty( $this -> rmt_fix_paths ) )
    {
        //$this -> npDump( 'buildRemoteURI', 'Attempting To Fix Possible Bad URI', $uri_parts );

        foreach( $this -> rmt_fix_paths AS $part => $match )
        {
            if ( ! empty( $match ) )
            {
                foreach( $match AS $match_str => $repl )
                {
                    $srch_str = NULL;

                    switch( $part )
                    {
                        case 'path':

                            if ( ! $chk_scheme )
                            {
                                $srch_str = $uri_parts['path'];
                            }

                        break;

                        case 'query':

                            if ( $chk_query )
                            {
                                $srch_str = $uri_parts['query'];
                            }

                        break;

                        case 'fname':

                            if ( is_string( $req_page_name ) )
                            {
                                $srch_str = $req_page_name;
                            }

                        break;

                    } // End Switch


                    if ( ! empty( $srch_str ) )
                    {
                        if ( (bool)FALSE !== stristr( $srch_str, $match_str ) )
                        {
                            //$this -> npDump( 'buildRemoteURI', 'BAD ' . $part . ' FOUND. Replacing With', $repl );
                            $uri_parts['scheme'] = $repl['scheme'];
                            $uri_parts['host']   = $repl['host'];
                            $uri_parts['path']   = $repl['path'];
                        }
                    }
                }
            }
        }
    }

    /**
     * Assemble The Final URI And Return
     */

    if ( $request && empty( $uri_parts['scheme'] ) )
    {
        $uri_parts['scheme'] = $root_parts['scheme'];
        $uri_parts['host']   = $root_parts['host'];
        $uri_parts['user']   = $this -> rmt_user;
        $uri_parts['pass']   = $this -> rmt_pass;
    }

    //$this -> npDump( 'buildRemoteURI', 'Final URI Array', $uri_parts );

    $uri = $this -> reverseParsedURI( $uri_parts );

    //$this -> npDump( 'buildRemoteURI', 'Reassembled URI, Return TRUE', $uri );

    if ( ! $request && ! $this -> npp_debug_link_ary )
    {
        $uri = base64_encode( $uri );
    }

    return (bool)TRUE;

} // End Method buildRemoteURI

/**
 * Reverse A Parsed URI
 *
 * @param array ( $uri_parts -> array of parts returned by parse_url() )
 *
 * @return string ( reassembled URI )
 */

function reverseParsedURI( $uri_parts )
{
    //$this -> npDump( 'reverseParsedURI', 'Reassembling Parsed URI', $uri_parts );

    $scheme = $user = $pass = $host = $port = $path = $query = $fragment = $uri = '';

    if ( ! empty( $uri_parts ) && is_array( $uri_parts ) )
    {
        foreach( $uri_parts AS $key => $part )
        {
            if ( $part != '' )
            {
                switch( $key )
                {
                    case 'scheme':

                        $add = ( strtolower( $part ) == 'mailto' )
                             ? ( ':' )
                             : ( '://' );

                        ${$key} = $part . $add;

                    break;

                    case 'user':

                        ${$key} = $part . ':';

                    break;

                    case 'pass':

                        ${$key} = $part . '@';

                    break;

                    case 'port':

                        ${$key} = ':' . $part;

                    break;

                    case 'query':

                        ${$key} = '?' . $part;

                    break;

                    case 'fragment':

                        ${$key} = '#' . $part;

                    break;

                    default:

                        ${$key} = $part;

                    break;
                }
            }
        }
    }

    $uri = $scheme . $user . $pass . $host . $port . $path . $query . $fragment;

    //$this -> npDump( 'reverseParsedURI', 'Reassembled URI Is', $uri );

    return $uri;

} // End Method reverseParsedURI

/**
 * Verify The Path Component Of A URI Is Valid
 *
 * Additionally, test the path for a potential filename
 *
 * @param string ( &$path -> reference to current URI/link path component )
 *
 * @return bool ( result of check for a possible filename in path )
 */

function verifyPath( &$path )
{
    //$this -> npDump( 'verifyPath', 'verifying path' , $path );

    $path_len   = strlen( $path );
    $path_parts = explode( '/', $path );
    $pagechk    = ( substr( $path, -1 ) !== '/' );

    // Reassemble Path With Correct Syntax If Required

    if ( $path_len >= 1 && substr( $path, 0, 1 ) !== '/' )
    {
        $new_path   = '/';

        foreach( $path_parts AS $key => $part )
        {
            if ( $part != '' && $part != '.' )
            {
                $new_path .= $part;

                if ( ( $key + 1 ) < sizeof( $path_parts ) )
                {
                    // Reinsert Forward Slashes

                    $new_path .= '/';
                }
                else if ( ! $pagechk )
                {
                    // Append Path With Forward Slash if filename Is Not Present

                    $new_path .= '/';
                }
            }
        }

        $path = $new_path;
    }

    return $pagechk;

} // End Method verifyPath

/**
 * Build An Array Of Possible Domain Names For Remote Host
 *
 * This method takes the different parts of the remote variables
 * that are related to domain names and builds them into an array
 * of possible valid domains that can then be compared to links within
 * the remote document body.
 *
 * @param array ( $multiary -> array of child class variables that contain domain info )
 * @param array ( $retary   -> current array of domain names )
 * @param array ( $key      -> current array key of multiarray used during recursion )
 *
 * @return array ( Array of possible domain names )
 */

function buildDomainArray( $multiary, $retary = NULL, $key = 0 )
{
    // Return Valid Domain Array If Finished Looping Through $multiary

    if ( $key >= sizeof( $multiary ) )
    {
       $this -> poss_domains = $retary;
       return;
    }

    //$this -> npDump( 'buildDomainArray', 'Recursive loop array key: ', $key );

    // Set Initial Array

    if ( $key == 0 )
    {
        for( $i = 0; $i <= sizeof( $multiary ); $i++ )
        {
            if ( ! empty( $multiary[ $i ] ) && is_array( $multiary[ $i ] ) )
            {
                $retary = $multiary[ $i ];
                break;
            }
        }

        $key = $i + 1;
    }

    // If Empty Array In $multiary, Recurse

    if ( empty( $multiary[ $key ] ) )
    {
        $key++;
        $this -> buildDomainArray( $multiary, $retary , $key );
    }

    /**
     * Assemble Domains
     *
     * First part is used if there is a nested array.
     * The only place this could/should occur is in the
     * $rmt_tlds array.
     *
     * Second part processes all the other arrays
     */

    // Part 1: Nested Array

    if ( is_array( $retary[0] ) )
    {
        foreach( $retary AS $pt )
        {
            if ( empty( $ary ) )
            {
                $newdom = $ary = $pt;
                continue;
            }

            foreach( $ary AS $dom )
            {
                foreach( $pt AS $part )
                {
                    $newdom[] = ( $part != '' )
                              ? ( $part . '.' . $dom )
                              : ( $dom );
                }
            }

            $ary = $newdom;
        }

        $retary = $newdom;
        $newdom = array();
    }

    // Part 2: Non-Nested Array

    foreach( $retary AS $dom )
    {
        foreach( $multiary[ $key ] AS $part )
        {
            $newdom[] = ( $part != '' )
                      ? ( $part . '.' . $dom )
                      : ( $dom );
        }
    }

    $key++;

    $this -> buildDomainArray( $multiary, $newdom, $key );

} // End Method buildDomainArray


// ############# FORMATTING METHODS ############# //


/**
 * Insert Custom Content Into The Local Body
 *
 * @param string ( &$body   -> body of text passed by reference )
 * @param string ( $string  -> string of text to add to body )
 * @param mixed  ( $where   -> string ( 'append' or 'prepend', or integer position )
 *
 * @return bool  ( silent return true on error )
 */

function insertContent( &$body, $string, $where )
{
    if ( empty( $string ) || empty( $where ) || $string == '' )
    {
        //$this -> npDump( 'insertContent', 'No Content To Add, Or Empty Arguments.  Skipping Content Insertion At Location ' . $where, $string );

        return (bool)TRUE;
    }

    //$this -> npDump( 'insertContent', 'Inserting Custom Content Into Body At Location ' . $where, $string );

    if ( $this -> add_insert_comm )
    {
        $com_open  = "\n" . '<!-- n_p_p mod -->' . "\n";
        $com_close = "\n" . '<!-- n_p_p end mod -->' . "\n";

        $string = $com_open . $string . $com_close;
    }

    switch( $where )
    {
        case 'prepend':

            $body = $string . $body;

        break;

        case 'append':

            $body = $body . $string;

        break;

        case ( is_integer( $where ) ):

            $pre_body  = substr( $body, 0, $where );
            $post_body = substr( $body, $where );

            $body = $pre_body . $string . $post_body;

        break;

    } // End Switch

    return (bool)TRUE;

} // End Method addContent

/**
 * Apply Child Class Pre & Post Scan Arrays To Local Body
 *
 * You may also pass a custom array to this method
 *
 * @param string ( $ary_name -> pre/post scan array name )
 * @param array  ( $opt_ary  -> optional array to use. Must be in same
 *                              format as pre/post arrays )
 *
 * @return bool ( silent return true on error )
 */

function applyFormatArray( $ary_name, $opt_ary = NULL )
{
    $status = NULL;
    $chk_ary = array( 'rmt_pre_scan', 'rmt_post_scan' );

    if ( empty( $opt_ary ) && ! is_string( $ary_name ) || ! in_array( $ary_name, $chk_ary ) )
    {
        //$this -> npDump( 'applyFormatArray', 'Invalid Array Name', $ary_name );

        return (bool)TRUE;
    }

    $use_ary = NULL;

    switch( $ary_name )
    {
        case 'rmt_pre_scan'  : $use_ary = $this -> rmt_pre_scan; break;

        case 'rmt_post_scan' : $use_ary = $this -> rmt_post_scan; break;

        DEFAULT              : $use_ary = $opt_ary; break;

    } // End Switch

    if ( ! empty( $use_ary ) )
    {
        //$this -> npDump( 'applyFormatArray', 'Formatting Body Using Array ' . $ary_name, $use_ary );

        if ( empty( $use_ary['opt'] ) ) { $use_ary['opt'] = NULL; }

        $this -> searchAndReplace(   $this -> local_body
                                   , $use_ary['rtype']
                                   , $use_ary['repl']
                                   , $use_ary['srch']
                                   , $use_ary['opt']
                                 );
    }

    return (bool)TRUE;

} // End Method applyFormatArray

/**
 * Format The Local Body
 *
 * @return bool
 */

function formatBody()
{
    $status = NULL;
    $body = $this -> local_body;

    if ( ! empty( $this -> rmt_disp_format ) )
    {
        foreach( $this -> rmt_disp_format AS $action => $param_arys )
        {
            $pos = 0;

            if ( empty( $this -> rmt_disp_format[ $action ] ) || empty( $param_arys ) )
            {
                continue;
            }

            switch( $action )
            {
                case 'cut_content':

                    //$this -> npDump( 'formatBody', 'CUTTING CONTENT', $param_arys );

                    $body = $this -> cutContent( $body, $param_arys );

                break;

                case 'add_tags':

                    //$this -> npDump( 'formatBody', 'ADDING TAGS', $param_arys );

                    $body = $this -> addTags( $body, $param_arys );

                break;

                case 'strip_tags':

                    //$this -> npDump( 'formatBody', 'STRIPPING TAGS FROM SUB-STRING', $param_arys );

                    $body = $this -> stripTags( $body, $param_arys );

                break;

                case 'replace':

                    if ( ! empty( $param_arys ) && is_array( $param_arys ) )
                    {
                        $this -> searchAndReplace(   $body
                                                   , $param_arys['rtype']
                                                   , $param_arys['repl']
                                                   , $param_arys['srch']
                                                   , $param_arys['opt']
                                                 );
                    }

                break;

            } // End Switch
        }
    }

    // Adding Content

    $content_ary = $this -> addContent();

    if ( $this -> is_multi_array( $content_ary ) )
    {
        foreach( $content_ary AS $add )
        {
            if ( ! empty( $add ) && sizeof( $add ) === 2 )
            {
                $this -> insertContent( $body, $add['content'], $add['where'] );
            }
        }
    }
    else
    {
        if ( ! empty( $content_ary ) && sizeof( $content_ary ) === 2 )
        {
            $this -> insertContent( $body, $content_ary['content'], $content_ary['where'] );
        }
    }

    $this -> local_body = $body;

    return (bool)TRUE;

} // End Method

/**
 * Set Pointer Position In Document
 *
 * @return void ( $pos passed by reference )
 */

function setPointer( &$body, &$pos, $reset, $posadj )
{
    $body_len = strlen( $body );
    $adj_chk  = empty( $posadj );
    $goto     = 0;

    if ( $reset && $adj_chk )
    {
        $pos = 0;
        return;
    }

    // Pointer Adjustment Required

    if ( ! $adj_chk )
    {
        if ( ! is_array( $posadj ) )
        {
            $tmppos = ( $posadj < 0 && $body_len > -( $posadj ) ) ? ( $body_len + $posadj ) : ( $posadj );
        }
        else
        {
            if ( $posadj[0] === 0 )
            {
                $goto = $pos;
            }
            else
            {
                if ( $posadj[0] === 2 )
                {
                    if ( $posadj[1][0] >= 0 )
                    {
                        $goto = 0;
                    }
                    else if ( $body_len > -( $posadj[1][0] ) )
                    {
                        $goto = $body_len + $posadj[1][0];
                    }
                }
                else if ( $posadj[1][0] < 0 )
                {
                    $goto = 0;
                }
            }

            $tmpstart = $this -> getStringPosition( $body, $posadj[2], 0, $goto, 0 );

            $tmppos = ( $tmpstart != $body_len ) ? ( $tmpstart + $posadj[1][1] ) : ( 0 );
        }

        $pos = ( ! empty( $tmppos ) ) ? ( $tmppos ) : ( 0 );
    }

    //$this -> npDump( 'setPointer', 'POINTER POSITION SET TO ' . $pos . ' Body Length Is ' . $body_len );

    return;

} // End Method

/**
 * Find The Position Of A Tag In The Document Body
 *
 * @param string  ( $body    -> body of text being processed )
 * @param string  ( $string  -> string to search for )
 * @param integer ( $loc     -> final location to place pointer at )
 * @param integer ( $pos     -> current position of pointer in $body )
 * @param integer ( $limit   -> limit search to this many characters from $pos )

 * @return integer ( position of tag )
 */

function getStringPosition( $body, $string, $loc, $pos, $limit )
{
    $this -> npp_sanitize -> body_length = strlen( $body );

    //$this -> npDump( 'getStringPosition', 'Searching For String Starting At position ' . $pos, $string );

    $newpos = $this -> npp_sanitize
                    -> findnxstr( $body, $pos, $string, is_array( $string ) );

    if ( is_array( $newpos ) )
    {
        if ( is_array( $limit ) )
        {
            $limit_key = array_keys( $string, $newpos[1] );
            $limit = $limit[ $limit_key ];
        }

        $tagpos = $newpos[0];
        $string = $newpos[1];
    }
    else
    {
        if ( is_array( $string ) ) { $string = $string[0]; }
        $tagpos = $newpos;
    }

    //$this -> npDump( 'getStringPosition', 'New Position Is ' . $tagpos . ' string = ' . htmlspecialchars( $string ) );

    if ( $tagpos > strlen( $body ) || ( $limit > 0 && $limit < ( $tagpos - $pos ) ) )
    {
        //$this -> npDump( 'getStringPosition', 'Char Limit Or End Of Body Reached While Searching For Tag', array( $tagpos, $pos, ( $tagpos - $pos ) ) );

        return strlen( $body );
    }

    if ( $loc == 1 )
    {
        //$this -> npDump( 'getStringPosition', 'Moving Pointer To End Of Search String' );

        $tagpos = $tagpos + strlen( $string );
    }

    //$this -> npDump( 'getStringPosition', 'Found Search String At Position ' . $tagpos . '. Dumping The next 20 characters', array( 'needle' => $string, 'next 20' => substr( $body, $tagpos, 20 ) ) );

    return $tagpos;

} // End Method getStringPosition


/**
 * Used To Perform Search And Replace On Remote Content
 * This is mostly for providing easy child class building
 * Without having the need to touch the parent class
 *
 * @param string  ( $body      -> reference to body of text being processed )
 * @param string  ( $scan_type -> what function to use )
 * @param mixed   ( $repl      -> replacement array or string )
 * @param mixed   ( $srch      -> search for array or string )
 * @param integer ( $opt       -> use for string length in substr replacements
 *                                ( also optional integer switch for PHP 5 support )
 *
 * @return array ( Array of possible domain names )
 */

function searchAndReplace( &$body, $scan_type, $repl, $srch = NULL, $opt = null )
{
    switch( $scan_type )
    {
        case 'str'   : $FUNC = 'str_replace';    break;

        case 'stri'  : $FUNC = ( $this -> checkPHPVersion( 5 ) )
                             ? ( 'str_ireplace' )
                             : ( 'str_replace' );break;

        case 'preg'  : $FUNC = 'preg_replace';   break;

        case 'ereg'  : $FUNC = 'ereg_replace';   break;

        case 'eregi' : $FUNC = 'eregi_replace';  break;

        case 'substr': $FUNC = 'substr_replace'; break;

        default      : $FUNC = 'str_replace';    break;

    } // End Switch

    //$this -> npDump( 'searchAndReplace', 'Attempting String Replacements Using Function ' . $FUNC, array( $srch, $repl ) );

    // For Substring Replacements, $srch Is An Integer Position

    if ( $scan_type == 'substr' )
    {
        // Check Incoming Array For Appropriate Elements and Data Type

        if ( ! is_string( $repl ) || ! is_integer( $srch ) )
        {
            //$this -> npDump( 'searchAndReplace', 'Incorrect Parameter Types For Substring Replacement', array( $srch, $repl ) );

            return $this -> returnError( 'wrong_type' );
        }
        else
        {
            if ( $opt == 0 )
            {
                //$this -> npDump( 'searchAndReplace', 'NOTHING TO REPLACE, RETURNING', $FUNC );

                return (bool)TRUE;
            }

            //$this -> npDump( 'searchAndReplace', 'Performing Substring Replacements. start position = ' . $srch . ' Num of chars to cut = ' . $opt );

            // Adding Line Feeds And Comments To Replacement String

            if ( $this -> add_insert_comm )
            {
                $com_open  = "\n" . '<!-- n_p_p mod -->' . "\n";
                $com_close = "\n" . '<!-- n_p_p end mod -->' . "\n";

                $repl = $com_open . $repl . $com_close;
            }

            if ( is_integer( $opt ) )
            {
                $body = $FUNC( $body, $repl, $srch, $opt );
            }
            else
            {
                $body = $FUNC( $body, $repl, $srch );
            }

            //$this -> npDump( 'searchAndReplace', 'SUB-STRING REPLACEMENT SUCCEEDED.' );
        }
    }
    else
    {
        // Adding Line Feeds To Replacement String

        if ( ! is_array( $repl ) ) { $repl = "\n" . $repl . "\n"; }

        if ( is_integer( $opt ) )
        {
             $body = $FUNC( $srch, $repl, $body, $opt );
        }
        else
        {
             $body = $FUNC( $srch, $repl, $body );
        }

        //$this -> npDump( 'searchAndReplace', 'STRING REPLACEMENTS SUCCEEDED.' );
    }

    return (bool)TRUE;

} // End Method searchAndReplace

/**
 * String Tags From A select portion of the body
 *
 * @param string ( $body    -> content to act on )
 * @param array  ( $striparys -> array of parameters to perform actions on body )
 *
 * @return string ( $body -> altered body of content )
 */

function stripTags( $body, $striparys )
{
    /**
     * Reference For Loop Array $stripit:
     *
     * array(   Search for tag to start stripping at
     *        , Where to start cutting ( 0 = beginning, 1 = end ) of tag
     *        , Search for tag to stop stripping at
     *        , Where to stop stripping ( 0 = beginning, 1 = end ) of tag
     *        , Array of parameters to pass to the santizer
     *        , Limit position hits to this many characters from starting position
     *        , Position To Start Looking From If You Know It
     *        , Reset position to 0 for next loop increment
     *      );
     */

    if ( empty( $striparys ) || empty( $striparys[0] ) )
    {
        return $body;
    }

    $body_len = strlen( $body );

    foreach( $striparys AS $stripit )
    {
        $this -> setPointer( $body, $pos, $stripit[7], $stripit[6] );

        $start_cut = $this -> getStringPosition( $body, $stripit[0], $stripit[1], $pos, $stripit[5] );
        $end_cut   = $this -> getStringPosition( $body, $stripit[2], $stripit[3], $start_cut, $stripit[5] );

        if (    $start_cut == $body_len
             || $end_cut == $body_len
             || $start_cut >= $end_cut
           )
        {
            //$this -> npDump( 'cutContent', 'Exceeded Char Limit, end of body reached, or 0 chars to cut.  Cut And Replace Content FAILED.<br />start position = ' . $start_cut . '<br />End cut = ' . $end_cut );

            $pos = 0;
            continue;
        }

        // Extract The Sub-String

        $strip_string = substr( $body, $start_cut, ( $end_cut - $start_cut ) );

        // Run Sub-String Through Sanitizer To Strip Any Tags

        $this -> sanitizeRemoteContent( $strip_string, $stripit[4] );

        // Do String Replacements In Sub-String If Required

        if ( ! empty( $stripit[9] ) && is_array( $stripit[9] ) )
        {
            $this -> searchAndReplace(   $strip_string
                                       , $stripit[9]['rtype']
                                       , $stripit[9]['repl']
                                       , $stripit[9]['srch']
                                       , $stripit[9]['opt']
                                     );
        }

        // Wrap The Sub-String In Tag Set If Required

        if ( ! empty( $stripit[8] ) && is_array( $stripit[8] ) )
        {
            $strip_string = "\n" . $stripit[8][0] . "\n" . $strip_string . "\n" . $stripit[8][1] . "\n";
        }

        // Replace Sub-String In Body.  Body Passed By Reference

        $this -> searchAndReplace(   $body
                                   , 'substr'
                                   , $strip_string
                                   , $start_cut
                                   , ( $end_cut - $start_cut )
                                 );


        $pos = $start_cut + strlen( $strip_string );
    }

    return $body;

} // End Method stripTags

/**
 * Cut And Insert Content From Body Of Text
 *
 * @param string ( $body    -> content to act on )
 * @param array  ( $cutarys -> array of parameters to perform actions on body )
 *
 * @return string ( $body -> altered body of content )
 */

function cutContent( $body, $cutarys )
{
    /**
     * Reference For Loop Array $cutit:
     *
     * array(   Search for tag to start cutting at
     *        , Where to start cutting ( 0 = beginning, 1 = end ) of tag
     *        , Search for tag to stop cutting at
     *        , Where to stop cutting ( 0 = beginning, 1 = end ) of tag
     *        , Content to insert if required
     *        , Limit position hits to this many characters from starting position
     *        , Position To Start Looking From If You Know It
     *        , Reset position to 0 for next loop increment
     *      );
     */

    if ( empty( $cutarys ) || empty( $cutarys[0] ) )
    {
        return $body;
    }

    foreach( $cutarys AS $cutit )
    {
        $this -> setPointer( $body, $pos, $cutit[7], $cutit[6] );

        $start_cut = $this -> getStringPosition( $body, $cutit[0], $cutit[1], $pos, $cutit[5] );
        $end_cut   = $this -> getStringPosition( $body, $cutit[2], $cutit[3], $start_cut, $cutit[5] );

        if (    $start_cut == $body_len
             || $end_cut == $body_len
             || $start_cut >= $end_cut
           )
        {
            //$this -> npDump( 'cutContent', 'Exceeded Char Limit, end of body reached, or 0 chars to cut.  Cut And Replace Content FAILED.<br />start position = ' . $start_cut . '<br />End cut = ' . $end_cut );

            $pos = 0;
            continue;
        }

        //$this -> npDump( 'cutContent', 'Cut And Replace Content.<br />start position = ' . $start_cut . '<br />Number of chars to cut = ' . ( $end_cut - $start_cut ) . '<br />cutting string: ', substr( $body, $start_cut, ( $end_cut - $start_cut ) ) );

        // Body Passed By Reference

        $this -> searchAndReplace(   $body
                                   , 'substr'
                                   , $cutit[4]
                                   , $start_cut
                                   , ( $end_cut - $start_cut )
                                 );

        $pos = $start_cut + strlen( $cutit[4] );
    }

    return $body;

} // End Method cutContent

/**
 * Add Tags To Document
 *
 * @param string ( $body    -> content to act on )
 * @param array  ( $addarys -> array of parameters to perform actions on body )
 *
 * @return string ( $body -> altered body of content )
 */

function addTags( $body, $addarys )
{
    /**
     * Reference For Loop Array $addit:
     *
     * array(   search for tag
     *        , where to insert ( 0 = beginning, 1 = end ) of tag
     *        , content to insert
     *        , search for tag ( optional -> to close a tag )
     *        , where to insert ( 0 = beginning, 1 = end ) of tag
     *        , content to insert
     *        , Limit Hits To This many characters From Starting Position
     *        , Position To Start Looking From If You Know It
     *        , Reset Position To 0 For Next Loop Increment
     *      );
     */

    if ( empty( $addarys ) || empty( $addarys[0] ) )
    {
        return $body;
    }

    foreach( $addarys AS $addit )
    {
        $this -> setPointer( $body, $pos, $addit[8], $addit[7] );

        // Insert Opening Tag

        $open_tag = $this -> getStringPosition( $body, $addit[0], $addit[1], $pos, $addit[6] );

        if ( $open_tag < strlen( $body ) )
        {
            //$this -> npDump( 'addTags', 'Adding Tag ' . htmlspecialchars( $addit[2] ) . ' At Position ' . $open_tag );

            $this -> insertContent( $body, $addit[2], $open_tag );

            $pos = $open_tag + strlen( $addit[2] );
        }
        else
        {
            //$this -> npDump( 'addTags', 'End of body or limit reached while searching for open tag INSERT position.  Skip closing and continue to next array element<br />Insert Open Tag Position = ' . $open_tag );

            continue;
        }

        // Process Closing Tag If Required

        if ( ! empty( $addit[3] ) && $addit[3] != '' )
        {
            $pos = 0;

            $close_tag = $this -> getStringPosition( $body, $addit[3], $addit[4], $open_tag, $addit[6] );

            if ( $close_tag >= strlen( $body ) )
            {
                //$this -> npDump( 'addTags', 'No closing tag to insert, limit, or end of body reached while searching for close tag INSERT position.<br />Continuing to next array element' );

                $pos = 0;
                continue;
            }

            //$this -> npDump( 'addTags', 'Adding Tag ' . htmlspecialchars( $addit[5] ) . ' At Position ' . $close_tag );

            $this -> insertContent( $body, $addit[5], $close_tag );

            $pos = $pos + strlen( $addit[5] );
        }
    }

    return $body;

} // End Method addTags

/**
 * Adjust A Form Query
 *
* @return bool ( silent return on error )
 */

function adjustFormQuery( &$query, $type )
{
    if (    empty( $this -> rmt_fix_form_query )
         || empty( $query )
         || empty( $type )
       )
    {
        return (bool)TRUE;
    }

    $ary = $this -> rmt_fix_form_query[ $type ];

    if ( empty( $ary['opt'] ) ) { $ary['opt'] = NULL; }

    $this -> searchAndReplace(   $this -> local_body
                               , $ary['rtype']
                               , $ary['repl']
                               , $ary['srch']
                               , $ary['opt']);

    return (bool)TRUE;

} // End Method

/**
 * Required N_P_P Comments And CSS Wrappers
 *
 * @return bool
 */

function wrapContent()
{
    // The following code is
    // required under N_P_P copyright.
    // DO NOT REMOVE

    //$this -> npDump( 'wrapContent', 'Wrapping Body With CSS Divisions And Adding Disclaimer' );

    $css_wrap_open  = '';
    $css_wrap_close = '';

    $disclaimer = "\nNested Page Project ( N_P_P ) Version " . $this -> npp_version . ", Copyright 2003.\nAuthor: Kiril Threndor ( support@nestedpage.illearth.net ).\nSupport: http://myphpnuke.com/\nLicense: GNU/GPL - http://www.gnu.org/copyleft/gpl.html\n\nThe N_P_P Author claims NO legal responsibility for how this script is used.\nIt is assumed that the appropriate permission(s) has been obtained for the use\nand linking of content from " . $this -> rmt_root . ".\n\nIF YOU THINK YOUR CONTENT IS BEING ILLEGALLY LINKED,\nPLEASE CONTACT THE ADMINISTRATOR AT " . $this -> local_root . ".\n\nThis original source of this page can be viewed at:\n" . $this -> rmt_request . "\n";

    $css_wrap_open .= "\n\n" . '<div id="' . $this -> npp_div_id . '">';
    $css_wrap_open .= "\n\n" . '<!--';
    $css_wrap_open .= $disclaimer;
    $css_wrap_open .= '-->' . "\n\n" . '<!-- Start N_P_P Embedded Content From ' . $this -> rmt_root . ' -->' . "\n\n";

    if ( $this -> wrap_content )
    {
        $css_wrap_open  .= '<div class="' . $this -> css_div_class . '">' . "\n";
        $css_wrap_close .= "\n" . '</div>';
    }

    $css_wrap_close .= translate( 'This Page Can Be Viewed Directly At' );

    $css_wrap_close .= ' &#058; <a href="' . $this -> rmt_request . '" title="' . $this -> rmt_site_name . ': ' . translate( 'Remote Source Page' ) . '" target="_blank">' . $this -> rmt_site_name . '</a>' . "\n";

    $css_wrap_close .= '<br /><br />' . "\n";

    $css_wrap_close .= "\n" . 'This Is A <a href="http://nestedpage.illearth.net/" target="_blank" title="Nested Page Project Web Site">N_P_P</a> Embedded Page';

    $css_wrap_close .= "\n\n" . '<!-- End N_P_P Embedded Content -->' . "\n\n" . '</div>' . "\n\n";

    $this -> local_body = $css_wrap_open . $this -> local_body . $css_wrap_close;

    return (bool)TRUE;

} // End Method wrapContent

/**
 * Child Class Empty Method
 *
 * This Method Should Be Redefined In The Child Class
 *
 * @return void
 */

function addContent()
{
    return NULL;

} // End Empty Method addContent


// ############# HELPER FUNCTIONS AND DEBUGGING ############# //


/**
 * Determine If An Array Is Multi-Dimensional
 *
 * @param array ( $array -> array to check )
 *
 * @return bool ( TRUE = Yes )
 */

function is_multi_array( $array )
{
    if ( is_array( $array ) && ! empty( $array ) )
    {
        $keys = array_keys( $array );

        foreach( $keys AS $v )
        {
            if ( ! is_array( $array[ $v ] ) )
            {
                continue;
            }
            else
            {
                return (bool)TRUE;
            }
        }
    }

    return (bool)FALSE;

} // End Method is_multi_array

/**
 * Page Redirect Handler
 *
 * @return void ( exit )
 */

function redirectRequest( $uri )
{
    if ( (bool)FALSE !== strpos( $_SERVER['SERVER_SOFTWARE'], 'IIS' ) )
    {
        @header( "Refresh: 0; url = $uri" );
    }
    else
    {
        @header( "Location: $uri" );
    }

    exit;

} // End Method redirectRequest

/**
 * Check PHP Version
 *
 * @return bool
 */

function checkPHPVersion( $version )
{
    $testSplit    = explode ( '.' , $version );
    $currentSplit = explode ( '.' , phpversion() );

    if ( $testSplit[0] < $currentSplit[0] ) { return (bool)TRUE; }

    if ( $testSplit[0] == $currentSplit[0] )
    {
        if ( $testSplit[1] < $currentSplit[1] ) { return (bool)TRUE; }

        if ( $testSplit[1] == $currentSplit[1] )
        {
            if ( $testSplit[2] <= $currentSplit[2] ) { return (bool)TRUE; }
        }
    }

    return (bool)FALSE;

}  // End Method checkPHPVersion

/**
 * Verify Child Variables Are Defined Properly
 *
 * This check can be toggled off by using the
 * bool switch "disable_child_verify" in the class
 * variables
 *
 * @return string ( error identifier for returnError method )
 */

function verifyChildVars()
{
    switch( TRUE )
    {
        case(    empty( $this -> rmt_site_id )
              || $this -> rmt_site_id == ''
            ):

            return 'bad_rmt_site_id';

        case(    empty( $this -> subsan_param )
              || $this -> subsan_param == ''
              || ! is_file( $this -> subclass_root . $this -> subsan_param )
            ):

            return 'bad_subsan_param';

        case(    empty( $this -> arg1_name )
              || $this -> arg1_name == ''
            ):

            return 'bad_arg1_name';

        case(    empty( $this -> arg2_name )
              || $this -> arg2_name == ''
            ):

            return 'bad_arg2_name';

        case(    empty( $this -> rmt_root )
              || ( strrchr( $this -> rmt_root, '/' ) !== '/' )
            ):

            return 'bad_root';

        case(    empty( $this -> rmt_root_dname )
              || $this -> rmt_root_dname == ''
            ):

            return 'bad_root_dname';

        case(    ! isset( $this -> rmt_root_sdnames )
              || ! is_array( $this -> rmt_root_sdnames )
            ):

            return 'bad_root_sdnames';

        case(    ! isset( $this -> rmt_tlds )
              || ! is_array( $this -> rmt_tlds )
            ):

            return 'bad_tld';

    } // End Switch

    return (bool)TRUE;

} // End Method verifyChildVars

/**
 * Method used to return error messages to user.
 *
 * If debugging, it also will dump limited debugging data
 * and a list of the current class variables values.
 *
 * Note: If Debugging, class will exit in this method.
 *
 * @param string ( $error -> identifies the error )
 * @param mixed  ( $data -> mixed data to be dumped if in debugging mode )
 *
 * @return string ( Error Message or exit if debugging )
 */

function returnError( $error = NULL, $debug_data = NULL )
{
    switch ( $error )
    {
        case 'param':

            $msg = 'Invalid Parameters, Cannot Continue';

            if ( $this -> npp_debug )
            {
                $debug_data = parse_url( $this -> local_root );
            }

        break;

        case 'remote_open':
            $msg = 'Remote Page Cannot Be Retrieved';
        break;

        case 'no_content':
            $msg = 'No Displayable Content Was Found';
        break;

        case 'include_open':
            $msg = 'Failed To Include A Required File';
        break;

        case 'class_fail':
            $msg = 'Failed To Instantiate Required Class';
        break;

        case 'not_avail':
            $msg = 'Feature Is Not Current Available In This Version OF N_P_P';
        break;

        default:
            $msg = 'Cannot Complete Your Request At This Time';
        break;

    } // End Switch

    if ( $this -> npp_debug )
    {
        var_dump( $error, $debug_data );

        echo "<br /><br /><br />\n";

        $this -> dumpClassVariables( 'NestedPageProject' );

        exit;
    }
    else
    {
        return $msg;
    }

} // End Method returnError

/**
 * Dump	Current	Values Of Class	Variables
 * Formatted For Easy Viewing In Web Browser
 *
 * @param string ( $classname -> Name of the class you want variables dumped for )
 *
 * @return void
 */

function dumpClassVariables( $classname )
{
	echo '<h1>Dumping Variables For Class ' . $classname . '</h1>';

	echo '<br />' . "\n";

	foreach( get_class_vars( $classname	) AS $key => $v	)
	{
		var_dump( "<b>Variable {$key}:</b> ", $this	-> $key	);

		echo "\n\n" . '<br /><br />' . "\n\n";
	}

	exit;

} // End Method	dumpVariables

/**
 * Used to debug/create child classes
 * Dumps extensive data at each error
 * and processing stage
 *
 * @param string ( $method -> Method name )
 * @param string ( $msg    -> Debugging message to display )
 * @param mixed  ( $data   -> Debugging data )
 *
 * @return void
 */

function npDump( $method, $msg = '', $data = '' )
{
    if ( $this -> npp_debug )
    {
        echo "\n\n" . '<br />' . "\n\n";

        echo '<b>Method ' . $method . ':</b> ' . $msg . "\n";

        echo "<br />&nbsp;&nbsp;Data Dump:&nbsp;&nbsp;\n";

        if ( is_array( $data ) )
        {
            foreach( $data AS $key => $v )
            {
                if ( is_string( $v ) )
                {
                    $v = nl2br( htmlspecialchars( $v ) );
                }

                echo "<br />\n";
                echo '&nbsp;&nbsp;Array Key ' . $key . ' = ' . $v;
            }
        }
        else
        {
            if ( is_string( $data ) )
            {
                $data = nl2br( htmlspecialchars( $data ) );
                echo "<br />\n";
                echo $data;
            }
            else
            {
                echo '&nbsp;&nbsp;' . var_dump( $data );
            }
        }
    }

    return;

} // End Method npDump

} // End Class NestedPageProject

?>