<?php

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

/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | myPHPNuke Version 188_8 RC2                                          |
// +----------------------------------------------------------------------+
// | License: GNU/GPL - http://www.gnu.org/copyleft/gpl.html              |
// +----------------------------------------------------------------------+
// | Support: http://myphpnuke.com/                                       |
// +----------------------------------------------------------------------+
// | Author: myPHPNuke Dev Team                                           |
// +----------------------------------------------------------------------+
// | Copyright: © 2001-2004 myPHPNuke Dev Team                            |
// +----------------------------------------------------------------------+
// $Id: core_Uploads.class.php,v 1.3.2.4 2004/08/15 12:58:24 kirilt Exp $


class MPN_Upload
{
    /**
     * Allowed file mime types
     * @var array
     */

    var $allowed_mime_types = array();

    /**
     * File mime type
     * @var string
     */

    var $mime_type = '';

    /**
     * File mime subtype
     * @var string
     */

    var $mime_subtype = '';

    /**
     * Maximum file size in bytes
     * @var integer
     */

    var $max_file_size = 0;

    /**
     * Original File Name
     *
     * File name after dissallow
     * characters have been replaced.
     *
     * @var string
     */

    var $orig_file_name = '';

    /**
     * Save Extension
     *
     * Intended for saving potentially
     * dangerous files to a web accessible
     * directory
     *
     * @var string
     */

    var $save_ext = '';

    /**
     * Optional Tracking ID
     *
     * Intended for identifying what
     * script initiated upload request
     *
     * @var integer
     */

    var $opt_id = 0;

    /**
     * This holds mPN2's _PATH constant
     * @var string
     */

    var $path = null;

    /**
     * Destination Directory Per MIME Type
     * @var string
     */

    var $save_dir = null;

    /**
     * Track Uploads In Database
     * @var string
     */

    var $track = FALSE;

    /**
     * Holds key for upload array
     * @var integer
     */

    var $key = 0;

     /**
     * File Name Prepend / Append String Array
     * @var array
     */

    var $_adj_name = array();

    /**
     * Check Image Dimensions
     * @var bool
     */

    var $_dimen_check = FALSE;

    /**
     * Attempt CHMOD Of Saved File If Writable
     * @var bool
     */

    var $_chmod_attempt = FALSE;

    /**
     * Default value to chmod files if
     * $_chmod_attempt is TRUE
     * @var integer
     */

    var $chmod = 0644;

    /**
     * Array of uploaded file names returned by php
     * @var array
     */

    var $_uploaded_name = array();

    /**
     * Array of uploaded file extensions extracted from $_uploaded_name
     * @var array
     */

    var $_uploaded_ext = array();

    /**
     * Array of uploaded file mime types returned by php
     * @var array
     */

    var $_uploaded_mimetype = array();

    /**
     * Array of uploaded file sizes returned by php
     * @var array
     */

    var $_uploaded_size = array();

    /**
     * Array of uploaded temporary files returned by php
     * @var array
     */

    var $_uploaded_tmp_name = array();

    /**
     * Array of uploaded file errors returned by php
     * @var array
     */

    var $_uploaded_error = array();

    /**
     * Array of regenerated uploaded file names
     * @var array
     */

    var $_gen_file_name = array();

    /**
     * Constructor
     *
     * @param array $upload_param
     *
     * @return void
     */

    function MPN_Upload( $upload_param )
    {
        $this -> path = __ROOT__;

        $this -> max_file_size = $upload_param['maxsize'];

        $this -> allowed_mime_types = $upload_param['mime_types'];

        $input_field_name = $upload_param['input_field_name'];

        // Stuff the class with data from the $_FILES array

        if ( ! empty( $_FILES ) )
        {
            $this -> _uploaded_name = $_FILES[ $input_field_name ]['name'];

            foreach( $this -> _uploaded_name AS $v )
            {
                $this -> _uploaded_ext[] = substr( strrchr( $v, '.' ) , 1 );
            }

            $this -> _uploaded_mimetype = $_FILES[ $input_field_name ]['type'];

            $this -> _uploaded_size = $_FILES[ $input_field_name ]['size'];

            $this -> _uploaded_tmp_name = $_FILES[ $input_field_name ]['tmp_name'];

            $this -> _uploaded_error = $_FILES[ $input_field_name ]['error'];
        }
        else
        {
            exit( 'Missing Required Variable.  Please Contact Your Administrator.' );
        }

        return;

    } // End Contructor

    /**
     * Sanitize and move upload to final destination
     *
     * @param array $upload_proc
     * @return array
     */

    function do_upload( $upload_proc = NULL )
    {
        if ( ! empty( $upload_proc ) )
        {
            $this -> _adj_name      =& $upload_proc['filename_adj'];

            $this -> _dimen_check   =& $upload_proc['check_dimen'];

            $this -> _chmod_attempt =& $upload_proc['attempt_chmod'];
        }

        foreach( $this -> _uploaded_error as $this -> key => $status )
        {
            // Check PHP Reported Error Status For Uploaded File

            switch( $status )
            {
                // No Error Reported

                case 0: break;

                // File Size Exceeds The Upload_Max_Filesize Directive In php.ini

                case 1:

                    return $this -> returnERROR( 'file_size_error', $this -> _uploaded_size[ $this -> key ] );

                break;

                // File Size Exceeds The Max_File_Size Directive In The Upload Form

                case 2:

                    return $this -> returnERROR( 'file_size_error', $this -> _uploaded_size[ $this -> key ] );

                break;

                // Incomplete Upload

                case 3:

                    return $this -> returnERROR( 'incomplete_upload', $this -> _uploaded_name[ $this -> key ] );

                break;

                // No File Uploaded

                case 4:

                    return $this -> returnERROR( 'no_upload', $_FILES );

                break;

                // Default Error For PHP Versions < 4.2.0

                default:

                    return $this -> returnERROR( 'invalid_file', $_FILES );

                break;
            }

            // Secondary Checks ( covers some issues with specific versions of PHP )

            if (    $this -> _uploaded_name[ $this -> key ] == ''
                 || ! ( $this -> _uploaded_size[ $this -> key ] > 0 )
                 || empty( $this -> _uploaded_tmp_name[ $this -> key ] )
                 || ! is_uploaded_file( $this -> _uploaded_tmp_name[ $this -> key ] ) )
            {
                return $this -> returnERROR( 'invalid_file', $_FILES );
            }

            // Valid Upload Found
            // Clean File Name And Set Original File Name Variable
            // Reset Uploaded File Name Variable

            $this -> orig_file_name = $this -> _uploaded_name[ $this -> key ] = $this -> cleanFilename( $this -> _uploaded_name[ $this -> key ] );

            // Prepend String To File Name If Required

            if ( isset( $this -> _adj_name['prepend'] ) )
            {
                $this -> _uploaded_name[ $this -> key ] = $this -> _adj_name['prepend'] . '_' . $this -> _uploaded_name[ $this -> key ];
            }

            // Append String To File Name If Required

            if ( isset( $this -> _adj_name['append'] ) )
            {
                switch( $this -> _adj_name['append'] )
                {
                    case 'usekey':

                        $this -> _adj_name['append'] =& $this -> key;

                    break;

                    case 'mime':

                        $this -> _adj_name['append'] = str_replace( '/', '-', $this -> _uploaded_mimetype[ $this -> key ] );

                    break;

                } // End Switch

                $tmp = explode( '.' , $this -> _uploaded_name[ $this -> key ] );
                $tmp[0] = $tmp[0] . '_' . $this -> _adj_name['append'];
                $this -> _uploaded_name[ $this -> key ] = implode( '.', $tmp );
            }

            // Verify File Is Allowed

            if ( (bool)TRUE !== ( $halt = $this -> verifyFile() ) )
            {
                return $halt;
            }

            // Save Uploaded File To Either Database Or File

            if ( is_array( $this -> save_dir ) )
            {
                if ( (bool)TRUE !== ( $halt = $this -> saveToDB() ) )
                {
                    return $halt;
                }

                // Attempt To Delete Temp File In The Event It Wasn't Auto Deleted

                unset( $this -> _uploaded_tmp_name[ $this -> key ] );
            }
            else
            {
                if ( (bool)TRUE !== ( $halt = $this -> saveToDirectory() ) )
                {
                    return $halt;
                }

                // Attempt To Delete Temp File In The Event It Wasn't Auto Deleted

                unset( $this -> _uploaded_tmp_name[ $this -> key ] );
            }

            // Add Final Uploaded File Name To Returned Array

            $this -> _gen_file_name[] = $this -> _uploaded_name[ $this -> key ];

        } // End Foreach

        return $this -> _gen_file_name;

    } // End Method do_upload

    /**
     * Verify File Is Valid & Allowed
     *
     * @return bool/array
     */

    function verifyFile()
    {
        // Set Current Files MIME Type & Subtype

        $this -> mime_type    = substr( $this -> _uploaded_mimetype[ $this -> key ], 0, ( strpos( $this -> _uploaded_mimetype[ $this -> key ], '/' ) ) );

        $this -> mime_subtype = substr( strrchr( $this -> _uploaded_mimetype[ $this -> key ] , '/' ) , 1 );

        // Check If Files MIME Type Is In Allowed Type Array

        if ( empty( $this -> allowed_mime_types[ $this -> mime_type ] ) || ! is_array( $this -> allowed_mime_types[ $this -> mime_type ] ) )
        {
            return $this -> returnERROR( 'file_type_error', $this -> mime_type );
        }
        else // Assign The Allowed Type Array To Temp Variable
        {
            $file_type =& $this -> allowed_mime_types[ $this -> mime_type ];
        }

        // Set Optional Tracking ID

        if ( isset( $file_type['destination']['opt_id'] ) )
        {
            $this -> opt_id = $file_type['destination']['opt_id'];
        }

        // Check MIME Subtype

        if ( ! is_array( $file_type['subtypes'] ) || ! in_array( $this -> mime_subtype, $file_type['subtypes'] ) )
        {
            return $this -> returnERROR( 'file_type_error', $this -> mime_subtype );
        }

        // Check File Size

        if ( $this -> _uploaded_size[ $this -> key ] > $this -> max_file_size )
        {
            return $this -> returnERROR( 'file_size_error', $this -> _uploaded_size[ $this -> key ] );
        }

        // Check File Extension

        if ( ! is_array( $file_type['extensions']['allow'] ) || ! in_array( $this -> _uploaded_ext[ $this -> key ], $file_type['extensions']['allow'] ) )
        {
            return $this -> returnERROR( 'file_extension_error', $this -> _uploaded_ext[ $this -> key ] );
        }

        // Replace File Extension If Required

        if ( isset( $file_type['extensions']['save_as'] ) )
        {
            $curr_ext = '.' . $this -> _uploaded_ext[ $this -> key ];

            if ( is_array( $file_type['extensions']['save_as'] ) )
            {
                $save_key = array_keys( $file_type['extensions']['allow'], $this -> _uploaded_ext[ $this -> key ] );

                $save_ext = '.' . $file_type['extensions']['save_as'][ $save_key ];
            }
            else
            {
                $save_ext = '.' . $file_type['extensions']['save_as'];
            }

            $this -> _uploaded_name[ $this -> key ] = $this -> _uploaded_name[ $this -> key ] . $save_ext;
        }

        // Check Dimensions If File Is Image

        if ( $this -> _dimen_check && isset( $file_type['dimensions'] ) )
        {
            // Images Types PHP function getimagesize() will check

            $check_types = array( 'gif', 'jpg', 'png', 'swf', 'psd', 'bmp', 'tiff', 'jpc', 'jp2', 'jpx', 'jb2', 'swc', 'iff' );

            if ( in_array( $this -> _uploaded_ext[ $this -> key ] , $check_types ) )
            {
                $size = @getimagesize( $this -> _uploaded_tmp_name[ $this -> key ] );

                if ( !  $size
                     || ! is_array( $file_type['dimensions'] )
                     || $size[0] > $file_type['dimensions']['width']
                     || $size[1] > $file_type['dimensions']['height'] )
                {
                    return $this -> returnERROR( 'file_dimension_error', $size );
                }
            }
        }

        // Set Destination Directory For This Image If Save Type Is File

        if (    (bool)FALSE === $file_type['destination']['db']
             && isset( $file_type['destination']['path'] )
             && ! empty( $this -> path ) )
        {
            if ( isset( $file_type['destination']['track'] ) )
            {
                $this -> track = $file_type['destination']['track'];
            }

            $this -> save_dir = $this -> path . $file_type['destination']['path'];

            // Verify Destination Directory Exists If Saving To File

            if (    empty( $this -> save_dir )
                 || ! file_exists( $this -> save_dir )
                 || is_file( $this -> save_dir )
                 || ! is_writable( $this -> save_dir ) )
            {
                return $this -> returnERROR( 'file_destination_error', $this -> save_dir );
            }
        }
        else  // Saving File To Database
        {
            $this -> save_dir = $file_type['destination'];
        }

        return (bool)TRUE;

    } // End Method verifyFile

   /**
     * Uploaded Filename Cleaning
     *
     * Returns filename with disallowed
     * characters stripped and spaces
     * replaced with underscore
     *
     * @return string
     */

    function cleanFilename( &$uploaded_filename )
    {
        $allowed_filename = strtolower( $uploaded_filename );

        // Replace spaces with _

        $allowed_filename = preg_replace( '/[\s]+/', '_', $allowed_filename );

        // Remove all chars except a-z0-9-_.

        $allowed_filename = preg_replace( '/[^a-z0-9\-_\.]+/', '', $allowed_filename );

        return $allowed_filename;

    } // End Method cleanFilename

    /**
     * Save Upload To A File
     *
     * @return bool/array
     */

    function saveToDirectory()
    {
        $save_file = $this -> save_dir . $this -> _uploaded_name[ $this -> key ];

        // Check For Existing File

        if ( file_exists( $save_file ) )
        {
            return $this -> returnERROR( 'file_exists_error', $this -> _uploaded_name[ $this -> key ] );
        }

        // Move Temp File To Destination Directory

        if ( (bool)FALSE === @move_uploaded_file( $this -> _uploaded_tmp_name[ $this -> key ] , $save_file ) )
        {
            if ( (bool)FALSE === @copy( $this -> _uploaded_tmp_name[ $this -> key ], $save_file ) )
            {
                return $this -> returnERROR( 'file_move_error', $this -> _uploaded_tmp_name[ $this -> key ] );
            }
        }

        // Attempt CHMOD Of File

        if ( is_writable( $save_file ) && $this -> _chmod_attempt )
        {
            if ( (bool)FALSE === @chmod( $save_file, $this -> chmod ) )
            {
                return $this -> returnERROR( 'file_chmod_error', $this -> _uploaded_tmp_name[ $this -> key ] );
            }
        }

        // If Database Tracking Is Desired, Add File Info To Table

        if ( (bool)TRUE === $this -> track )
        {
            if ( (bool)TRUE !== ( $halt = $this -> trackFileUploads( $save_file ) ) )
            {
                return $halt;
            }
        }

        return (bool)TRUE;

    } // End Method saveToDirectory

    /**
     * Save Upload To Database
     *
     * Intended for definition in sub-class
     * in order to keep the class portable
     *
     * @return bool/array
     */

    function saveToDB()
    {
        return $this -> returnERROR( 'method_not_defined', $this -> save_dir );

    } // End Method saveToDB

    /**
     * Track Uploads
     *
     * Intended for definition in sub-class
     * in order to keep the class portable
     *
     * Only used when saving file to a directory
     *
     * @return bool/array
     */

    function trackFileUploads()
    {
        return $this -> returnERROR( 'method_not_defined', $this -> save_dir );

    } // End Method trackFileUploads

    /**
     * Error Processing
     *
     * @return array
     */

    function returnERROR( $error, $data = NULL )
    {
        // Array Of Error Messages, Array Key Is Error Type

        $message = array
        (
            'incomplete_upload'      => 'Incomplete File Upload'

          , 'no_upload'              => 'No File Specified For Uploading'

          , 'invalid_file'           => 'Invalid File'

          , 'file_type_error'        => 'You Are Not Allowed To Upload This Type Of File'

          , 'file_size_error'        => 'File exceeds maximum allowed filesize'

          , 'file_extension_error'   => 'You Are Not Allowed To Upload This Type Of File'

          , 'file_dimension_error'   => 'Image exceeds maximum allowed width or height'

          , 'file_destination_error' => 'Destination Directory Does Not Exist.  Please Contact Your Administrator'

          , 'file_exists_error'      => 'Invalid File Name, Please Rename Your File'

          , 'file_move_error'        => 'Unable To Move File To Destination Directory.  Please Contact Your Administrator'

          , 'file_chmod_error'       => 'Unable To CHMOD File'

          , 'method_not_defined'     => 'Database Method Not Defined.  Please Contact Your Administrator'

          , 'file_save_error'        => 'Unable To Save File.  Please Contact Your Administrator'

          , 'temp_file_error'        => 'Temp File Error.  Please Contact Your Administrator'

        );

        return array( 'status' => TRUE , 'error' => $error , 'message' => $message[$error] , 'data' => $data );

    } // End Method returnERROR

} // End Class mPN2_upload

?>
