* Invision Power Services * IP.Board v3.1.4 * Extended Member Functions. Disparate functions that are not required * on every page view. * Last Updated: $Date: 2010-08-05 19:11:01 -0400 (Thu, 05 Aug 2010) $ * * * @author $Author: bfarber $ (Original: MattMecham) * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license http://www.invisionpower.com/community/board/license.html * @package IP.Board * @link http://www.invisionpower.com * @since Tuesday 1st March 2005 (11:52) * @version $Revision: 6731 $ * */ class memberFunctions { /**#@+ * Registry objects * * @access protected * @var object */ public $registry; public $DB; public $settings; public $request; public $lang; public $member; public $memberData = array( 'member_id' => 0 ); /**#@-*/ /** * Image class * * @access public * @var object */ public $classImage; /** * Constructor * * @access public * @param object Main Registry Object * @return void */ public function __construct( ipsRegistry $registry ) { /* Make objects */ $this->registry = $registry; $this->DB = $this->registry->DB(); $this->settings =& $this->registry->fetchSettings(); $this->request =& $this->registry->fetchRequest(); $this->member = $this->registry->member(); if( is_object($this->registry->member()) ) { $this->memberData =& $this->registry->member()->fetchMemberData(); } $this->cache = $this->registry->cache(); $this->caches =& $this->registry->cache()->fetchCaches(); } /** * Updates member's DB row name or members_display_name * * @todo [Future] Separate out forum specific stuff (moderators, etc) and move into hooks * @access public * @param string Member id * @param string New name * @param string Field to update (name or display name) * @return mixed True if update successful, otherwise exception or false * Error Codes: * NO_USER Could not load the user * NO_PERMISSION This user cannot change their display name at all * NO_MORE_CHANGES The user cannot change their display name again in this time period * NO_NAME No display name (or shorter than 3 chars was given) * ILLEGAL_CHARS The display name contains illegal characters * USER_NAME_EXISTS The username already exists */ public function updateName( $member_id, $name, $field='members_display_name' ) { //----------------------------------------- // Load the member //----------------------------------------- $member = IPSMember::load( $member_id ); $_seoName = IPSText::makeSeoTitle( $name ); if ( ! $member['member_id'] ) { throw new Exception( "NO_USER" ); } //----------------------------------------- // Make sure name does not exist //----------------------------------------- try { if ( $this->checkNameExists( $name, $member, $field ) === TRUE ) { throw new Exception( "USER_NAME_EXISTS" ); } else { if ( $field == 'members_display_name' ) { $this->DB->force_data_type = array( 'dname_previous' => 'string', 'dname_current' => 'string' ); $this->DB->insert( 'dnames_change', array( 'dname_member_id' => $member_id, 'dname_date' => time(), 'dname_ip_address' => $member['ip_address'], 'dname_previous' => $member['members_display_name'], 'dname_current' => $name ) ); //----------------------------------------- // Still here? Change it then //----------------------------------------- IPSMember::save( $member['member_id'], array( 'core' => array( 'members_display_name' => $name, 'members_l_display_name' => mb_strtolower( $name ), 'members_seo_name' => $_seoName ) ) ); $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->update( 'forums', array( 'last_poster_name' => $name, 'seo_last_name' => $_seoName ), "last_poster_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'member_name' => 'string', 'seo_name' => 'string' ); $this->DB->update( 'sessions', array( 'member_name' => $name, 'seo_name' => $_seoName ), "member_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'starter_name' => 'string', 'seo_first_name' => 'string' ); $this->DB->update( 'topics', array( 'starter_name' => $name, 'seo_first_name' => $_seoName ), "starter_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->update( 'topics', array( 'last_poster_name' => $name, 'seo_last_name' => $_seoName ), "last_poster_id=" . $member['member_id'] ); } else { //----------------------------------------- // If one gets here, one can assume that the new name is correct for one, er...one. // So, lets do the converteroo //----------------------------------------- IPSMember::save( $member['member_id'], array( 'core' => array( 'name' => $name, 'members_l_username' => mb_strtolower( $name ) ) ) ); $this->DB->force_data_type = array( 'member_name' => 'string' ); $this->DB->update( 'moderators', array( 'member_name' => $name ), "member_id=" . $member['member_id'] ); if ( ! $this->settings['auth_allow_dnames'] ) { //----------------------------------------- // Not using sep. display names? //----------------------------------------- IPSMember::save( $member['member_id'], array( 'core' => array( 'members_display_name' => $name, 'members_l_display_name' => mb_strtolower( $name ), 'members_seo_name' => $_seoName ) ) ); $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->update( 'forums', array( 'last_poster_name' => $name, 'seo_last_name' => $_seoName ), "last_poster_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'member_name' => 'string', 'seo_name' => 'string' ); $this->DB->update( 'sessions', array( 'member_name' => $name, 'seo_name' => $_seoName ), "member_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'starter_name' => 'string', 'seo_first_name' => 'string' ); $this->DB->update( 'topics', array( 'starter_name' => $name, 'seo_first_name' => $_seoName ), "starter_id=" . $member['member_id'] ); $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->update( 'topics', array( 'last_poster_name' => $name, 'seo_last_name' => $_seoName ), "last_poster_id=" . $member['member_id'] ); } } //----------------------------------------- // Recache moderators //----------------------------------------- $this->registry->cache()->rebuildCache( 'moderators', 'forums' ); //----------------------------------------- // Recache announcements //----------------------------------------- $this->registry->cache()->rebuildCache( 'announcements', 'forums' ); //----------------------------------------- // Stats to Update? //----------------------------------------- $this->registry->cache()->rebuildCache( 'stats', 'core' ); IPSLib::runMemberSync( 'onNameChange', $member['member_id'], $name ); return TRUE; } } catch( Exception $error ) { throw new Exception( $error->getMessage() ); } } /** * Cleans a username or display name, also checks for any errors * * @access public * @param string $name Username or display name to clean and check * @param array $member [ Optional Member Array ] * @param string $field name or members_display_name * @return array Returns an array with 2 keys: 'username' OR 'members_display_name' => the cleaned username, 'errors' => Any errors found **/ public function cleanAndCheckName( $name, $member=array(), $field='members_display_name' ) { //----------------------------------------- // Clean the name first //----------------------------------------- $cleanedName = $this->_cleanName( $name, $field ); if( count($cleanedName['errors']) ) { if( $field == 'members_display_name' ) { return array( 'members_display_name' => $cleanedName['name'], 'errors' => array( 'dname' => $cleanedName['errors'][0] ) ); } else { return array( 'username' => $cleanedName['name'], 'errors' => array( 'username' => $cleanedName['errors'][0] ) ); } } //----------------------------------------- // Name is clean, make sure it doesn't exist //----------------------------------------- try { if( !$this->checkNameExists( $cleanedName['name'], $member, $field, true, true ) ) { if( $field == 'members_display_name' ) { return array( 'members_display_name' => $cleanedName['name'], 'errors' => array() ); } else { return array( 'username' => $cleanedName['name'], 'errors' => array() ); } } else { if( $field == 'members_display_name' ) { return array( 'members_display_name' => $cleanedName['name'], 'errors' => array( 'dname' => 'reg_error_username_taken' ) ); } else { return array( 'username' => $cleanedName['name'], 'errors' => array( 'username' => 'reg_error_username_taken' ) ); } } } catch( Exception $e ) { //----------------------------------------- // Name exists, let's return appropriately //----------------------------------------- if( $field == 'members_display_name' ) { switch( $e->getMessage() ) { case 'NO_NAME': return array( 'members_display_name' => $cleanedName['name'], 'errors' => array( 'dname' => 'reg_error_no_name' ) ); break; case 'ILLEGAL_CHARS': return array( 'members_display_name' => $cleanedName['name'], 'errors' => array( 'dname' => 'reg_error_chars' ) ); break; } } else { switch( $e->getMessage() ) { case 'NO_NAME': return array( 'username' => $cleanedName['name'], 'errors' => array( 'username' => 'reg_error_username_none' ) ); break; case 'ILLEGAL_CHARS': return array( 'username' => $cleanedName['name'], 'errors' => array( 'username' => 'reg_error_chars' ) ); break; } } } } /** * Check for an existing display or user name * * @access public * @param string Name to check * @param array [ Optional Member Array ] * @param string name or members_display_name * @param bool Ignore display name changes check (e.g. for registration) * @param bool Do not clean name again (e.g. coming from cleanAndCheckName) * @return mixed Either an exception or ( true if name exists. False if name DOES NOT exist ) * Error Codes: * NO_PERMISSION This user cannot change their display name at all * NO_MORE_CHANGES The user cannot change their display name again in this time period * NO_NAME No display name (or shorter than 3 chars was given) * ILLEGAL_CHARS The display name contains illegal characters */ public function checkNameExists( $name, $member=array(), $field='members_display_name', $ignore=false, $cleaned=false ) { if( ! $cleaned ) { $cleanedName = $this->_cleanName( $name, $field ); $name = $cleanedName['name']; if( count($cleanedName['errors']) ) { throw new Exception( $cleanedName['errors'][0] ); } } //----------------------------------------- // INIT //----------------------------------------- $error = ""; $banFilters = array(); $_timeCheck = time() - 86400 * $this->memberData['g_dname_date']; $member = is_array($member) ? $member : array(); $checkField = ( $field == 'members_display_name' ) ? 'members_l_display_name' : 'members_l_username'; //----------------------------------------- // Public checks //----------------------------------------- if ( IPS_AREA != 'admin' AND $ignore != true ) { if ( ! $this->settings['auth_allow_dnames'] OR $member['g_dname_changes'] < 1 OR $member['g_dname_date'] < 1 ) { throw new Exception( "NO_PERMISSION" ); } /* Check new permissions */ $_g = $this->caches['group_cache'][ $member['member_group_id'] ]; if ( $_g['g_displayname_unit'] ) { if ( $_g['gbw_displayname_unit_type'] ) { /* days */ if ( $member['joined'] > ( time() - ( 86400 * $_g['g_displayname_unit'] ) ) ) { throw new Exception( "NO_PERMISSION" ); } } else { /* Posts */ if ( $member['posts'] < $_g['g_displayname_unit'] ) { throw new Exception( "NO_PERMISSION" ); } } } //----------------------------------------- // Grab # changes > 24 hours //----------------------------------------- if( $member['member_id'] ) { $name_count = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count, MIN(dname_date) as min_date', 'from' => 'dnames_change', 'where' => "dname_member_id=" . $member['member_id'] . " AND dname_date > $_timeCheck" ) ); $name_count['count'] = intval( $name_count['count'] ); $name_count['min_date'] = intval( $name_count['min_date'] ) ? intval( $name_count['min_date'] ) : $_timeCheck; if ( intval( $name_count['count'] ) >= $member['g_dname_changes'] ) { throw new Exception( "NO_MORE_CHANGES" ); } } } //----------------------------------------- // Load ban filters //----------------------------------------- $this->DB->build( array( 'select' => '*', 'from' => 'banfilters' ) ); $this->DB->execute(); while( $r = $this->DB->fetch() ) { $banFilters[ $r['ban_type'] ][] = $r['ban_content']; } //----------------------------------------- // Are they banned [NAMES]? //----------------------------------------- if ( IPS_AREA != 'admin' ) { if ( is_array( $banFilters['name'] ) and count( $banFilters['name'] ) ) { foreach ( $banFilters['name'] as $n ) { if ( $n == "" ) { continue; } $n = str_replace( '\*', '.*' , preg_quote($n, "/") ); if ( preg_match( "/^{$n}$/i", $name ) ) { return TRUE; break; } } } } //----------------------------------------- // Check for existing name. //----------------------------------------- /* Load the handler if it's not present */ if( ! $this->han_login ) { $classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/handlers/han_login.php', 'han_login' ); $this->han_login = new $classToLoad( $this->registry ); $this->han_login->init(); } if( $member['member_id'] ) { $this->han_login->nameExistsCheck( $name, $member, $checkField ); if( $this->han_login->return_code AND $this->han_login->return_code != 'METHOD_NOT_DEFINED' AND $this->han_login->return_code != 'NAME_NOT_IN_USE' ) { return TRUE; } } $this->DB->build( array( 'select' => "{$field}, member_id", 'from' => 'members', 'where' => $checkField . "='" . $this->DB->addSlashes( mb_strtolower($name) ) . "'" . ( $member['member_id'] ? " AND member_id != " . $member['member_id'] : '' ), 'limit' => array( 0,1 ) ) ); $this->DB->execute(); //----------------------------------------- // Got any results? //----------------------------------------- if ( $this->DB->getTotalRows() ) { return TRUE; } //----------------------------------------- // Not allowed to select another's log in name //----------------------------------------- if ( $field == 'members_display_name' AND $this->settings['auth_dnames_nologinname'] ) { $check_name = $this->DB->buildAndFetch( array( 'select' => "{$field}, member_id", 'from' => 'members', 'where' => "members_l_username='" . $this->DB->addSlashes( mb_strtolower($name) ) . "'", 'limit' => array( 0,1 ) ) ); if ( $this->DB->getTotalRows() ) { if ( !$member['member_id'] OR $check_name['member_id'] != $member['member_id'] ) { return TRUE; } } } if ( $field == 'name' AND $this->settings['auth_dnames_nologinname'] ) { $check_name = $this->DB->buildAndFetch( array( 'select' => "{$field}, member_id", 'from' => 'members', 'where' => "members_l_display_name='" . $this->DB->addSlashes( mb_strtolower($name) ) . "'", 'limit' => array( 0,1 ) ) ); if ( $this->DB->getTotalRows() ) { if ( !$member['member_id'] OR $check_name['member_id'] != $member['member_id'] ) { return TRUE; } } } //----------------------------------------- // Test for unicode name //----------------------------------------- $unicodeName = $this->_getUnicodeName( $name ); if ( $unicodeName != $name ) { //----------------------------------------- // Check for existing name. //----------------------------------------- $this->DB->build( array( 'select' => "members_display_name, member_id, email", 'from' => 'members', 'where' => $checkField . "='". $this->DB->addSlashes( mb_strtolower($unicodeName) ) . "'" . ( $member['member_id'] ? " AND member_id != " . $member['member_id'] : '' ), 'limit' => array( 0,1 ) ) ); $this->DB->execute(); //----------------------------------------- // Got any results? //----------------------------------------- if ( $this->DB->getTotalRows() ) { return TRUE; } } return FALSE; } /** * Clean a username or display name * * @access protected * @param string Name * @param string Field (name or members_display_name) * @return array array( 'name' => $cleaned_name, 'errors' => array() ) */ protected function _cleanName( $name, $field='members_display_name' ) { $original = $name; $name = trim($name); if( $field == 'name' ) { // Commented out for bug report #15354 //$name = str_replace( '|', '|' , $name ); /* Remove multiple spaces */ $name = preg_replace( "/\s{2,}/", " ", $name ); } //----------------------------------------- // Remove line breaks //----------------------------------------- if( ipsRegistry::$settings['usernames_nobr'] ) { $name = IPSText::br2nl( $name ); $name = str_replace( "\n", "", $name ); $name = str_replace( "\r", "", $name ); } //----------------------------------------- // Remove sneaky spaces //----------------------------------------- if ( ipsRegistry::$settings['strip_space_chr'] ) { /* use hexdec to convert between '0xAD' and chr */ $name = IPSText::removeControlCharacters( $name ); } //----------------------------------------- // Trim after above ops //----------------------------------------- $name = trim( $name ); //----------------------------------------- // Test unicode name //----------------------------------------- $unicode_name = $this->_getUnicodeName( $name ); //----------------------------------------- // Do we have a name? //----------------------------------------- if( $field == 'name' OR ( $field == 'members_display_name' AND ipsRegistry::$settings['auth_allow_dnames'] ) ) { if( ! $name OR IPSText::mbstrlen( $name ) < 3 OR IPSText::mbstrlen( $name ) > ipsRegistry::$settings['max_user_name_length'] ) { ipsRegistry::getClass( 'class_localization' )->loadLanguageFile( array( 'public_register' ), 'core' ); $key = $field == 'members_display_name' ? 'reg_error_no_name' : 'reg_error_username_none'; $text = sprintf( ipsRegistry::getClass( 'class_localization' )->words[ $key ], ipsRegistry::$settings['max_user_name_length'] ); //----------------------------------------- // Only show note about special chars when relevant //----------------------------------------- if( strpos( $name, '&' ) !== false ) { $text .= ipsRegistry::getClass( 'class_localization' )->words['reg_error_no_name_spec']; } return array( 'name' => $original, 'errors' => array( $text ) ); } } //----------------------------------------- // Blocking certain chars in username? //----------------------------------------- if( ipsRegistry::$settings['username_characters'] ) { $check_against = preg_quote( ipsRegistry::$settings['username_characters'], "/" ); $check_against = str_replace( '\-', '-', $check_against ); // Fix for bug #20998 if( !preg_match( "/^[" . $check_against . "]+$/iu", $name ) ) { return array( 'name' => $original, 'errors' => array( str_replace( '{chars}', ipsRegistry::$settings['username_characters'], ipsRegistry::$settings['username_errormsg'] ) ) ); } } //----------------------------------------- // Manually check against bad chars //----------------------------------------- if( strpos( $unicode_name, '\' ) !== false OR strpos( $unicode_name, '&#quot;' ) !== false OR strpos( $unicode_name, '$' ) !== false OR strpos( $unicode_name, '&#lt;' ) !== false OR strpos( $unicode_name, '$' ) !== false OR strpos( $unicode_name, ']' ) !== false OR strpos( $unicode_name, '[' ) !== false OR strpos( $unicode_name, ',' ) !== false OR strpos( $unicode_name, '|' ) !== false OR strpos( $unicode_name, '&#gt;' ) !== false ) { ipsRegistry::getClass( 'class_localization' )->loadLanguageFile( array( 'public_register' ), 'core' ); return array( 'name' => $original, 'errors' => array( ipsRegistry::getClass( 'class_localization' )->words['reg_error_chars'] ) ); } return array( 'name' => $name, 'errors' => array() ); } /** * Get unicode version of name * * @access protected * @param string Name * @return string Unicode Name */ protected function _getUnicodeName( $name ) { $unicode_name = preg_replace_callback( '/&#([0-9]+);/si', create_function( '$matches', 'return chr($matches[1]);' ), $name ); $unicode_name = str_replace( "'" , ''', $name ); $unicode_name = str_replace( "\\", '\', $name ); return $unicode_name; } /** * Upload personal photo function * Assumes all security checks have been performed by this point * * @access public * @param integer [Optional] member id instead of current member * @return array [ error (error message), status (status message [ok/fail] ) ] */ public function uploadPhoto( $member_id = 0 ) { //----------------------------------------- // INIT //----------------------------------------- $return = array( 'error' => '', 'status' => '', 'final_location' => '', 'final_width' => '', 'final_height' => '', 't_final_location' => '', 't_final_width' => '', 't_final_height' => '' ); $delete_photo = intval( $_POST['delete_photo'] ); $member_id = $member_id ? intval($member_id) : intval( $this->memberData['member_id'] ); $real_name = ''; $upload_dir = ''; $final_location = ''; $final_width = ''; $final_height = ''; $t_final_location = ''; $t_final_width = ''; $t_final_height = ''; $t_real_name = ''; $t_height = 50; $t_width = 50; if( !$member_id ) { return array( 'status' => 'cannot_find_member' ); } list($p_max, $p_width, $p_height) = explode( ":", $this->memberData[ 'g_photo_max_vars' ] ); $this->settings[ 'disable_ipbsize'] = 0 ; //----------------------------------------- // Sort out upload dir //----------------------------------------- /* Fix for bug 5075 */ $this->settings['upload_dir'] = str_replace( '.', '.', $this->settings['upload_dir'] ); $upload_path = $this->settings['upload_dir']; # Preserve original path $_upload_path = $this->settings['upload_dir']; //----------------------------------------- // Already a dir? //----------------------------------------- if ( ! file_exists( $upload_path . "/profile" ) ) { if ( @mkdir( $upload_path . "/profile", 0777 ) ) { @file_put_contents( $upload_path . '/profile/index.html', '' ); @chmod( $upload_path . "/profile", 0777 ); # Set path and dir correct $upload_path .= "/profile"; $upload_dir = "profile/"; } else { # Set path and dir correct $upload_dir = ""; } } else { # Set path and dir correct $upload_path .= "/profile"; $upload_dir = "profile/"; } //----------------------------------------- // Deleting the photo? //----------------------------------------- if ( $delete_photo ) { $memberData = IPSMember::load( $member_id ); $bwOptions = IPSBWOptions::thaw( $memberData['fb_bwoptions'], 'facebook' ); $bwOptions['fbc_s_pic'] = 0; $this->removeUploadedPhotos( $member_id, $upload_path ); IPSMember::save( $member_id, array( 'extendedProfile' => array( 'pp_main_photo' => '', 'pp_main_width' => 0, 'pp_main_height' => 0, 'pp_thumb_photo' => '', 'pp_thumb_width' => 0, 'pp_thumb_height' => 0, 'fb_photo' => '', 'fb_photo_thumb' => '', 'fb_bwoptions' => IPSBWOptions::freeze( $bwOptions, 'facebook' ) ) ) ); $return['status'] = 'deleted'; return $return; } //----------------------------------------- // Lets check for an uploaded photo.. //----------------------------------------- if ( $_FILES['upload_photo']['name'] != "" and ($_FILES['upload_photo']['name'] != "none" ) ) { //----------------------------------------- // Are we allowed to upload this photo? //----------------------------------------- if ( $p_max < 0 ) { $return['status'] = 'fail'; $return['error'] = 'no_photo_upload_permission'; } //----------------------------------------- // Remove any uploaded photos... //----------------------------------------- $this->removeUploadedPhotos( $member_id, $upload_path ); $real_name = 'photo-'.$member_id; //----------------------------------------- // Load the library //----------------------------------------- require_once( IPS_KERNEL_PATH.'classUpload.php' ); $upload = new classUpload(); //----------------------------------------- // Set up the variables //----------------------------------------- $upload->out_file_name = 'photo-'.$member_id; $upload->out_file_dir = $upload_path; $upload->max_file_size = $p_max * 1024; $upload->upload_form_field = 'upload_photo'; //----------------------------------------- // Populate allowed extensions //----------------------------------------- if ( is_array( $this->cache->getCache('attachtypes') ) and count( $this->cache->getCache('attachtypes') ) ) { foreach( $this->cache->getCache('attachtypes') as $data ) { if ( $data['atype_photo'] ) { if( $data['atype_extension'] == 'swf' AND $this->settings['disable_flash'] ) { continue; } $upload->allowed_file_ext[] = $data['atype_extension']; } } } //----------------------------------------- // Upload... //----------------------------------------- $upload->process(); //----------------------------------------- // Error? //----------------------------------------- if ( $upload->error_no ) { switch( $upload->error_no ) { case 1: // No upload $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; case 2: // Invalid file ext $return['status'] = 'fail'; $return['error'] = 'invalid_file_extension'; break; case 3: // Too big... $return['status'] = 'fail'; $return['error'] = 'upload_to_big'; break; case 4: // Cannot move uploaded file $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; case 5: // Possible XSS attack (image isn't an image) $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; } return $return; } //----------------------------------------- // Still here? //----------------------------------------- $real_name = $upload->parsed_file_name; $t_real_name = $upload->parsed_file_name; //----------------------------------------- // Check image size... //----------------------------------------- if ( ! $this->settings['disable_ipbsize'] ) { $imageDimensions = getimagesize( $upload_path . '/' . $real_name ); //----------------------------------------- // Main photo //----------------------------------------- if( $imageDimensions[0] > $p_width OR $imageDimensions[1] > $p_height ) { require_once( IPS_KERNEL_PATH."classImage.php" ); require_once( IPS_KERNEL_PATH."classImageGd.php" ); $image = new classImageGd(); $image->init( array( 'image_path' => $upload_path, 'image_file' => $real_name, ) ); $return = $image->resizeImage( $p_width, $p_height ); $image->writeImage( $upload_path . '/' . 'photo-'.$member_id . '.' . $upload->file_extension ); $t_real_name = $return['thumb_location'] ? $return['thumb_location'] : $real_name; $im['img_width'] = $return['newWidth'] ? $return['newWidth'] : $image->cur_dimensions['width']; $im['img_height'] = $return['newHeight'] ? $return['newHeight'] : $image->cur_dimensions['height']; } else { $im['img_width'] = $imageDimensions[0]; $im['img_height'] = $imageDimensions[1]; } //----------------------------------------- // MINI photo //----------------------------------------- if( $imageDimensions[0] > $t_width OR $imageDimensions[1] > $t_height ) { require_once( IPS_KERNEL_PATH . "classImage.php" ); require_once( IPS_KERNEL_PATH . "classImageGd.php" ); $image = new classImageGd(); $image->init( array( 'image_path' => $upload_path, 'image_file' => $t_real_name, ) ); $return = $image->resizeImage( $t_width, $t_height ); $image->writeImage( $upload_path . '/' . 'photo-thumb-'.$member_id . '.' . $upload->file_extension ); $t_im['img_width'] = $return['newWidth']; $t_im['img_height'] = $return['newHeight']; $t_im['img_location'] = count($return) ? 'photo-thumb-'.$member_id . '.' . $upload->file_extension : $real_name; } else { $_data = IPSLib::scaleImage( array( 'max_height' => $t_height, 'max_width' => $t_width, 'cur_width' => $im['img_width'], 'cur_height' => $im['img_height'] ) ); $t_im['img_width'] = $_data['img_width']; $t_im['img_height'] = $_data['img_height']; $t_im['img_location'] = $real_name; } } else { //----------------------------------------- // Main photo //----------------------------------------- $w = intval($this->request['man_width']) ? intval($this->request['man_width']) : $p_width; $h = intval($this->request['man_height']) ? intval($this->request['man_height']) : $p_height; $im['img_width'] = $w > $p_width ? $p_width : $w; $im['img_height'] = $h > $p_height ? $p_height : $h; //----------------------------------------- // Mini photo //----------------------------------------- $_data = IPSLib::scaleImage( array( 'max_height' => $t_height, 'max_width' => $t_width, 'cur_width' => $im['img_width'], 'cur_height' => $im['img_height'] ) ); $t_im['img_width'] = $_data['img_width']; $t_im['img_height'] = $_data['img_height']; $t_im['img_location'] = $real_name; } //----------------------------------------- // Check the file size (after compression) //----------------------------------------- if ( filesize( $upload_path . "/" . $real_name ) > ( $p_max * 1024 ) ) { @unlink( $upload_path . "/" . $real_name ); // Too big... $return['status'] = 'fail'; $return['error'] = 'upload_to_big'; return $return; } //----------------------------------------- // Main photo //----------------------------------------- $final_location = $upload_dir . $real_name; $final_width = $im['img_width']; $final_height = $im['img_height']; //----------------------------------------- // Mini photo //----------------------------------------- $t_final_location = $upload_dir . $t_im['img_location']; $t_final_width = $t_im['img_width']; $t_final_height = $t_im['img_height']; } else { $return['status'] = 'ok'; return $return; } //----------------------------------------- // Return... //----------------------------------------- $return['final_location'] = $final_location; $return['final_width'] = $final_width; $return['final_height'] = $final_height; $return['t_final_location'] = $t_final_location; $return['t_final_width'] = $t_final_width; $return['t_final_height'] = $t_final_height; $return['status'] = 'ok'; return $return; } /** * Upload background image * Assumes all security checks have been performed by this point * * @access public * @param integer [Optional] member id instead of current member * @return array [ error (error message), status (status message [ok/fail] ) ] */ public function uploadBackgroundImage( $member_id = 0 ) { //----------------------------------------- // INIT //----------------------------------------- $return = array( 'error' => '', 'status' => '', 'final_location' => '' ); $member_id = $member_id ? intval($member_id) : intval( $this->memberData['member_id'] ); $p_max = $this->memberData['g_max_bgimg_upload'] ? intval( $this->memberData['g_max_bgimg_upload'] ) : 999999999; $real_name = ''; $upload_dir = ''; $final_location = ''; if( ! $member_id ) { return array( 'status' => 'cannot_find_member' ); } //----------------------------------------- // Sort out upload dir //----------------------------------------- /* Fix for bug 5075 */ $this->settings['upload_dir'] = str_replace( '.', '.', $this->settings['upload_dir'] ); $upload_path = $this->settings['upload_dir']; # Preserve original path $_upload_path = $this->settings['upload_dir']; //----------------------------------------- // Already a dir? //----------------------------------------- if ( ! file_exists( $upload_path . "/bgimages" ) ) { if ( @mkdir( $upload_path . "/bgimages", 0777 ) ) { @file_put_contents( $upload_path . '/bgimages/index.html', '' ); @chmod( $upload_path . "/bgimages", 0777 ); # Set path and dir correct $upload_path .= "/bgimages"; $upload_dir = "bgimages/"; } else { # Set path and dir correct $upload_dir = ""; } } else { # Set path and dir correct $upload_path .= "/bgimages"; $upload_dir = "bgimages/"; } //----------------------------------------- // Lets check for an uploaded photo.. //----------------------------------------- if ( $_FILES['bg_upload']['name'] != "" and ($_FILES['bg_upload']['name'] != "none" ) ) { //----------------------------------------- // Are we allowed to upload this photo? //----------------------------------------- if ( $p_max < 0 ) { $return['status'] = 'fail'; $return['error'] = 'no_bgimg_upload_permission'; } //----------------------------------------- // Remove any uploaded photos... //----------------------------------------- $this->removeUploadedBackgroundImages( $member_id ); $real_name = 'bgimg-'.$member_id; //----------------------------------------- // Load the library //----------------------------------------- require_once( IPS_KERNEL_PATH.'classUpload.php' ); $upload = new classUpload(); //----------------------------------------- // Set up the variables //----------------------------------------- $upload->out_file_name = 'bgimg-'.$member_id; $upload->out_file_dir = $upload_path; $upload->max_file_size = $p_max * 1024; $upload->upload_form_field = 'bg_upload'; //----------------------------------------- // Populate allowed extensions //----------------------------------------- if ( is_array( $this->cache->getCache('attachtypes') ) and count( $this->cache->getCache('attachtypes') ) ) { foreach( $this->cache->getCache('attachtypes') as $data ) { if ( $data['atype_photo'] ) { if( $data['atype_extension'] == 'swf' AND $this->settings['disable_flash'] ) { continue; } $upload->allowed_file_ext[] = $data['atype_extension']; } } } //----------------------------------------- // Upload... //----------------------------------------- $upload->process(); //----------------------------------------- // Error? //----------------------------------------- if ( $upload->error_no ) { switch( $upload->error_no ) { case 1: // No upload $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; case 2: // Invalid file ext $return['status'] = 'fail'; $return['error'] = 'invalid_file_extension'; break; case 3: // Too big... $return['status'] = 'fail'; $return['error'] = 'upload_to_big'; break; case 4: // Cannot move uploaded file $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; case 5: // Possible XSS attack (image isn't an image) $return['status'] = 'fail'; $return['error'] = 'upload_failed'; break; } return $return; } //----------------------------------------- // Still here? //----------------------------------------- $real_name = $upload->parsed_file_name; $t_real_name = $upload->parsed_file_name; //----------------------------------------- // Check the file size (after compression) //----------------------------------------- if ( filesize( $upload_path . "/" . $real_name ) > ( $p_max * 1024 ) ) { @unlink( $upload_path . "/" . $real_name ); // Too big... $return['status'] = 'fail'; $return['error'] = 'upload_to_big'; return $return; } //----------------------------------------- // Main //----------------------------------------- $final_location = $upload_dir . $real_name; } else { $return['status'] = 'ok'; return $return; } //----------------------------------------- // Return... //----------------------------------------- $return['final_location'] = $final_location; $return['status'] = 'ok'; return $return; } /** * Remove member uploaded photos * * @access public * @param integer Member ID * @param string [Optional] Directory to check * @return array [ error (error message), status (status message [ok/fail] ) ] */ public function removeUploadedPhotos( $id, $upload_path='' ) { //----------------------------------------- // INIT //----------------------------------------- $upload_path = $upload_path ? $upload_path : $this->settings['upload_dir']; //----------------------------------------- // Already a dir? //----------------------------------------- if ( ! file_exists( $upload_path . "/profile" ) ) { if ( @mkdir( $upload_path . "/profile", 0777 ) ) { @file_put_contents( $upload_path . '/index.html', '' ); @chmod( $upload_path . "/profile", 0777 ); # Set path and dir correct $upload_path .= "/profile"; } } else { # Set path and dir correct $upload_path .= "/profile"; //----------------------------------------- // Only try to delete if we didn't just create dir //----------------------------------------- foreach( array( 'swf', 'jpg', 'jpeg', 'gif', 'png' ) as $ext ) { if ( @file_exists( $upload_path."/photo-".$id.".".$ext ) ) { @unlink( $upload_path."/photo-".$id.".".$ext ); } if ( @file_exists( $upload_path."/photo-thumb-".$id.".".$ext ) ) { @unlink( $upload_path."/photo-thumb-".$id.".".$ext ); } } } } /** * Remove member uploaded background images * * @access public * @param integer Member ID * @param string [Optional] Directory to check * @return array [ error (error message), status (status message [ok/fail] ) ] */ public function removeUploadedBackgroundImages( $id, $upload_path='' ) { //----------------------------------------- // INIT //----------------------------------------- $upload_path = $upload_path ? $upload_path : $this->settings['upload_dir']; //----------------------------------------- // Already a dir? //----------------------------------------- if ( ! file_exists( $upload_path . "/bgimages" ) ) { if ( @mkdir( $upload_path . "/bgimages", 0777 ) ) { @file_put_contents( $upload_path . '/index.html', '' ); @chmod( $upload_path . "/bgimages", 0777 ); # Set path and dir correct $upload_path .= "/bgimages"; } } else { # Set path and dir correct $upload_path .= "/bgimages"; //----------------------------------------- // Only should bother trying to delete if we didn't // just create the folder //----------------------------------------- foreach( array( 'swf', 'jpg', 'jpeg', 'gif', 'png' ) as $ext ) { if ( @file_exists( $upload_path."/bgimg-".$id.".".$ext ) ) { @unlink( $upload_path."/bgimg-".$id.".".$ext ); } } } } /** * Remove member's avatar * * @access public * @param int Member's ID * @return mixed Exception or true * * Exception Codes: * NO_MEMBER_ID: A valid member ID was not passed. * NO_PERMISSION: You do not have permission to change the avatar * */ public function removeAvatar( $member_id ) { //----------------------------------------- // Get member //----------------------------------------- $member = IPSMember::load( $member_id, 'extendedProfile, groups' ); if ( ! $member['member_id'] ) { throw new Exception( "NO_MEMBER_ID" ); } //----------------------------------------- // Allowed to upload pics for administrators? //----------------------------------------- if ( IPS_AREA != 'public' ) { if ( $member['g_access_cp'] AND !$this->registry->getClass('class_permissions')->checkPermission( 'member_photo_admin', 'members', 'members' ) ) { throw new Exception( "NO_PERMISSION" ); } } //----------------------------------------- // Actaully remove it.. //----------------------------------------- if ( $member['avatar_type'] == 'upload' ) { foreach( array( 'swf', 'jpg', 'jpeg', 'gif', 'png' ) as $ext ) { if ( @file_exists( $this->settings['upload_dir'] . "/av-" . $member_id . "." . $ext ) ) { @unlink( $this->settings['upload_dir'] . "/av-" . $member_id . "." . $ext ); } } } IPSMember::save( $member_id, array( 'extendedProfile' => array( 'avatar_type' => '', 'avatar_location' => '', 'avatar_size' => '' ) ) ); if ( IPS_AREA != 'public' ) { $this->registry->getClass('adminFunctions')->saveAdminLog("Member's avatar removed ( member_id: {$member_id} )"); } return TRUE; } /** * Saves the member's avatar * * @param INT Member's ID to save * @param string Upload field name [Default is "upload_avatar"] * @param string Avatar URL Field [Default is "avatar_url"] * @param string Gallery Avatar Directory Field [Default is "avatar_gallery"] * @param string Gallery Avatar Image Field [Default is "avatar_image"] * @author Brandon Farber, Stolen By Matt 'Haxor' Mecham * * Excepton Codes: * NO_MEMBER_ID: A valid member ID was not passed. * NO_PERMISSION: You do not have permission to change the avatar * UPLOAD_NO_IMAGE: Nothing to upload * UPLOAD_INVALID_FILE_EXT: Incorrect file extension (not an image) * UPLOAD_TOO_LARGE: Upload is larger than allowed * UPLOAD_CANT_BE_MOVED: Upload cannot be moved into the uploads directory * UPLOAD_NOT_IMAGE: Upload is not an image, despite what the file extension says! * NO_AVATAR_TO_SAVE: Nothing to save! * */ public function saveNewAvatar( $member_id, $uploadFieldName='upload_avatar', $urlFieldName='avatar_url', $galleryFieldName='avatar_gallery', $avatarGalleryImage='avatar_image', $gravatarFieldName='gravatar_email' ) { //----------------------------------------- // INIT //----------------------------------------- $avatar = array(); list($p_width, $p_height) = explode( "x", strtolower( $this->settings['avatar_dims'] ) ); if ( ! $member_id ) { throw new Exception( "NO_MEMBER_ID" ); } $member = IPSMember::load( $member_id, 'extendedProfile,groups' ); if ( ! $member['member_id'] ) { throw new Exception( "NO_MEMBER_ID" ); } //----------------------------------------- // Allowed to upload pics for administrators? //----------------------------------------- if ( IPS_AREA != 'public' ) { if ( $member['g_access_cp'] AND !$this->registry->getClass('class_permissions')->checkPermission( 'member_photo_admin', 'members', 'members' ) ) { throw new Exception( "NO_PERMISSION" ); } } //----------------------------------------- // Upload? //----------------------------------------- if( $_FILES[$uploadFieldName]['name'] != "" AND $_FILES[$uploadFieldName]['name'] != "none" ) { $this->settings[ 'upload_dir'] = str_replace( '.', '.', $this->settings['upload_dir'] ); $real_name = 'av-' . $member_id; require_once( IPS_KERNEL_PATH.'classUpload.php' ); $upload = new classUpload(); $upload->out_file_name = $real_name; $upload->out_file_dir = $this->settings['upload_dir']; $upload->max_file_size = $this->settings['avup_size_max'] * 1024; $upload->upload_form_field = $uploadFieldName; //----------------------------------------- // Populate allowed extensions //----------------------------------------- if ( is_array( $this->cache->getCache('attachtypes') ) and count( $this->cache->getCache('attachtypes') ) ) { foreach( $this->cache->getCache('attachtypes') as $data ) { if ( $data['atype_photo'] ) { if( $data['atype_extension'] == 'swf' AND $this->settings['disable_flash'] ) { continue; } $upload->allowed_file_ext[] = $data['atype_extension']; } } } //----------------------------------------- // Upload... //----------------------------------------- $upload->process(); //----------------------------------------- // Error? //----------------------------------------- if ( $upload->error_no ) { switch( $upload->error_no ) { case 1: // No upload throw new Exception("UPLOAD_NO_IMAGE"); break; case 2: // Invalid file ext throw new Exception("UPLOAD_INVALID_FILE_EXT"); break; case 3: // Too big... throw new Exception("UPLOAD_TOO_LARGE"); break; case 4: // Cannot move uploaded file throw new Exception("UPLOAD_CANT_BE_MOVED"); break; case 5: // Possible XSS attack (image isn't an image) throw new Exception("UPLOAD_NOT_IMAGE"); break; } } $real_name = $upload->parsed_file_name; $im = array(); if ( ! $this->settings['disable_ipbsize'] and $upload->file_extension != '.swf' ) { $imageDimensions = getimagesize( $this->settings['upload_dir'] . '/' . $real_name ); if( $imageDimensions[0] > $p_width OR $imageDimensions[1] > $p_height ) { require_once( IPS_KERNEL_PATH."classImage.php" ); require_once( IPS_KERNEL_PATH."classImageGd.php" ); $image = new classImageGd(); $image->init( array( 'image_path' => $this->settings['upload_dir'], 'image_file' => $real_name, ) ); $return = $image->resizeImage( $p_width, $p_height ); $image->writeImage( $this->settings['upload_dir'] . '/' . $real_name ); $im['img_width'] = $return['newWidth'] ? $return['newWidth'] : $image->cur_dimensions['width']; $im['img_height'] = $return['newHeight'] ? $return['newHeight'] : $image->cur_dimensions['height']; } else { $im['img_width'] = $imageDimensions[0]; $im['img_height'] = $imageDimensions[1]; } } else { $w = intval($this->request['man_width']) ? intval($this->request['man_width']) : $p_width; $h = intval($this->request['man_height']) ? intval($this->request['man_height']) : $p_height; $im['img_width'] = $w > $p_width ? $p_width : $w; $im['img_height'] = $h > $p_height ? $p_height : $h; } //----------------------------------------- // Set the "real" avatar.. //----------------------------------------- $avatar['avatar_location'] = $real_name; $avatar['avatar_size'] = $im['img_width'].'x'.$im['img_height']; $avatar['avatar_type'] = 'upload'; } //----------------------------------------- // URL? //----------------------------------------- else if( $this->request[ $urlFieldName ] AND IPSText::xssCheckUrl( $this->request[ $urlFieldName ] ) === true ) { $ext = explode ( ",", $this->settings['avatar_ext'] ); $checked = 0; $av_ext = preg_replace( "/^.*\.(\S+)$/", "\\1", $this->request[$urlFieldName] ); foreach( $ext as $v ) { if( strtolower( $v ) == strtolower( $av_ext ) ) { if( $v == 'swf' AND $this->settings['disable_flash'] ) { throw new Exception("INVALID_FILE_EXT"); } $checked = 1; break; } } if( $checked != 1 ) { throw new Exception("INVALID_FILE_EXT"); } if ( ! $this->settings['disable_ipbsize'] ) { if ( ! $img_size = @getimagesize( $this->request[$urlFieldName] ) ) { $img_size[0] = $p_width; $img_size[1] = $p_height; } $im = IPSLib::scaleImage( array( 'max_width' => $p_width, 'max_height' => $p_height, 'cur_width' => $img_size[0], 'cur_height' => $img_size[1] ) ); } else { $w = intval($this->request['man_width']) ? intval($this->request['man_width']) : $p_width; $h = intval($this->request['man_height']) ? intval($this->request['man_height']) : $p_height; $im['img_width'] = $w > $p_width ? $p_width : $w; $im['img_height'] = $h > $p_height ? $p_height : $h; } $avatar['avatar_location'] = trim( $this->request[ $urlFieldName ] ); $avatar['avatar_size'] = $im['img_width'].'x'.$im['img_height']; $avatar['avatar_type'] = 'url'; } //----------------------------------------- // Local image? //----------------------------------------- else if( isset($this->request[ $galleryFieldName ]) AND $this->request[ $avatarGalleryImage ] ) { $directory = ''; if( $this->request[$galleryFieldName] ) { $directory = preg_replace( "/[^\s\w_-]/", "", urldecode( $this->request[$galleryFieldName] ) ); if( $directory ) { $directory .= '/'; } } // BUG #20822 if( function_exists( 'mb_ereg_replace' ) ) { $filename = mb_ereg_replace( "/[^\s\w\._\-\[\]\(\)]/", "", urldecode( $this->request[$avatarGalleryImage] ) ); } else { $filename = preg_replace( "/[^\s\w\._\-\[\]\(\)]/", "", urldecode( $this->request[$avatarGalleryImage] ) ); } if( file_exists( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_avatars/' . $directory . $filename ) ) { $avatar['avatar_location'] = $directory . $filename; $avatar['avatar_size'] = ''; $avatar['avatar_type'] = 'local'; } } else if( $this->request[ $gravatarFieldName ] && $this->request[ $gravatarFieldName ] && $this->settings['allow_gravatars'] ) { $avatar['avatar_location'] = strtolower($this->request[ $gravatarFieldName ]); $avatar['avatar_type'] = 'gravatar'; } //----------------------------------------- // No avatar image? //----------------------------------------- if ( ! count($avatar) ) { throw new Exception("NO_AVATAR_TO_SAVE"); } //----------------------------------------- // Remove old uploaded avatars if needed //----------------------------------------- else if( $avatar['avatar_type'] != 'upload' ) { foreach( array( 'swf', 'jpg', 'jpeg', 'gif', 'png' ) as $ext ) { if ( @file_exists( $this->settings['upload_dir'] . "/av-" . $member_id . "." . $ext ) ) { @unlink( $this->settings['upload_dir'] . "/av-" . $member_id . "." . $ext ); } } } //----------------------------------------- // Store and redirect //----------------------------------------- IPSMember::save( $member_id, array( 'extendedProfile' => $avatar ) ); return TRUE; } /** * Grab all images within a particular avatar gallery directory * * @access public * @param string Selected category name * @return array Array of image names */ public function getHostedAvatarsFromCategory( $catName ) { $catName = IPSText::alphanumericalClean( $catName, ' ' ); // Commented out because alphanumericalClean removes spaces $images = array(); $path = ''; if ( ! $catName ) { $path = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_avatars'; } else if ( $catName == 'none' ) { return ''; } else { $path = DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_avatars/' . $catName; } if ( ! is_dir( $path ) ) { return FALSE; } try { foreach( new DirectoryIterator( $path ) as $file ) { if ( ! $file->isDot() AND $file->isFile() AND strpos( $file->getFilename(), '.' ) !== 0 ) { $_name = $file->getFilename(); $image_properties = @getimagesize( $path . '/' . $_name ); if( is_array($image_properties) AND count($image_properties) AND isset($image_properties[2]) ) { $images[] = $_name; } } } } catch ( Exception $e ) {} natcasesort($images); //usort( $images, array( $this, '_sortAvatars' ) ); reset( $images ); return $images; } /** * Grab all hosted avatar gallery directories * * @access public * @author Brandon Farber, Matt Mecham * @return array Array of hosted avatar cats */ public function getHostedAvatarCategories() { $av_categories = array(); if( is_dir( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_avatars' ) ) { try { foreach( new DirectoryIterator( DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_avatars' ) as $file ) { if ( ! $file->isDot() AND $file->isDir() ) { $_name = $file->getFileName(); if ( substr( $_name, 0, 1 ) != '.' ) { $av_categories[] = array( $_name, str_replace( "_", " ", $_name ) ); } } } } catch ( Exception $e ) {} usort( $av_categories, array( $this, '_sortAvatars' ) ); reset( $av_categories ); } return $av_categories; } /** * usort method for avatar categories * * @access private * @param string A string to compare * @param string B string to compare * @return void Sort order algorithm */ private function _sortAvatars( $a, $b ) { $aa = mb_strtolower($a[1]); $bb = mb_strtolower($b[1]); if ( $aa == $bb ) return 0; return ( $aa > $bb ) ? 1 : -1; } }