diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 5ff271d..6e2be82 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,60 +1,37 @@ filter: + paths: + - 'inc/*' + - '*' excluded_paths: - 'languages/*' - 'lib/*' - 'tests/*' - paths: - - 'inc/*' - - '*' tools: - php_cpd: - excluded_dirs: - - lib - - tests - - languages - filter: - excluded_paths: ['languages/*', 'lib/*', 'tests/*'] - php_pdepend: - excluded_dirs: - - lib - - tests php_mess_detector: filter: excluded_paths: ['languages/*', 'lib/*', 'tests/*'] - php_analyzer: - filter: - excluded_paths: ['languages/*', 'lib/*', 'tests/*'] - config: - parameter_reference_check: true - checkstyle: { enabled: true, no_trailing_whitespace: true, naming: { enabled: false, local_variable: '', abstract_class_name: '', utility_class_name: '', constant_name: '', property_name: '', method_name: '', parameter_name: '', interface_name: '', type_name: '', exception_name: '', isser_method_name: '' } } - unreachable_code: true - check_access_control: true - typo_checks: true - check_variables: true - suspicious_code: { enabled: true, overriding_parameter: true, overriding_closure_use: true, parameter_closure_use_conflict: true, parameter_multiple_times: true, non_existent_class_in_instanceof_check: true, non_existent_class_in_catch_clause: true, assignment_of_null_return: true, non_commented_switch_fallthrough: true, non_commented_empty_catch_block: true, overriding_private_members: true, use_statement_alias_conflict: true, precedence_in_condition_assignment: true } - dead_assignments: true - verify_php_doc_comments: { enabled: true, parameters: true, return: true, suggest_more_specific_types: true, ask_for_return_if_not_inferrable: true, ask_for_param_type_annotation: true } - loops_must_use_braces: false - check_usage_context: { enabled: false, method_call_on_non_object: { enabled: false, ignore_null_pointer: false }, foreach: { value_as_reference: false, traversable: false }, missing_argument: false, argument_type_checks: disabled } - simplify_boolean_return: true - phpunit_checks: false - reflection_checks: false - precedence_checks: { enabled: false, assignment_in_condition: false, comparison_of_bit_result: false } - basic_semantic_checks: true - doc_comment_fixes: true - reflection_fixes: true - use_statement_fixes: { enabled: false, remove_unused: false, preserve_multiple: false, order_alphabetically: false } php_code_sniffer: filter: excluded_paths: ['languages/*', 'lib/*', 'tests/*'] config: standard: WordPress - sensiolabs_security_checker: + tab_width: '2' + sniffs: { wordpress: { arrays: { array_declaration_sniff: true }, classes: { valid_class_name_sniff: true }, files: { file_name_sniff: true }, formatting: { multiple_statement_alignment_sniff: true }, functions: { function_call_signature_sniff: true, function_declaration_argument_spacing_sniff: true }, naming_conventions: { valid_function_name_sniff: true }, objects: { object_instantiation_sniff: true }, php: { discouraged_functions_sniff: true }, strings: { double_quote_usage_sniff: true }, white_space: { control_structure_spacing_sniff: true, operator_spacing_sniff: true, php_indent_sniff: true }, xss: { escape_output_sniff: true } } } + sensiolabs_security_checker: true + php_cpd: + excluded_dirs: + - lib + - tests + - languages filter: excluded_paths: ['languages/*', 'lib/*', 'tests/*'] php_loc: names: - 1: 'inc/*.php' + - 'inc/*.php' + excluded_dirs: + - lib + - tests + php_pdepend: excluded_dirs: - lib - tests diff --git a/.travis.yml b/.travis.yml index da996a1..ba7d077 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,24 +9,16 @@ php: env: - WP_VERSION=master WP_MULTISITE=0 - WP_VERSION=master WP_MULTISITE=1 + - WP_VERSION=3.7.1 WP_MULTISITE=0 + - WP_VERSION=3.7.1 WP_MULTISITE=1 + - WP_VERSION=3.6.1 WP_MULTISITE=0 + - WP_VERSION=3.6.1 WP_MULTISITE=1 - WP_VERSION=3.5.2 WP_MULTISITE=0 - WP_VERSION=3.5.2 WP_MULTISITE=1 - - WP_VERSION=3.5.1 WP_MULTISITE=0 - - WP_VERSION=3.5.1 WP_MULTISITE=1 - - WP_VERSION=3.5 WP_MULTISITE=0 - - WP_VERSION=3.5 WP_MULTISITE=1 - WP_VERSION=3.4.2 WP_MULTISITE=0 - WP_VERSION=3.4.2 WP_MULTISITE=1 - - WP_VERSION=3.4.1 WP_MULTISITE=0 - - WP_VERSION=3.4.1 WP_MULTISITE=1 - - WP_VERSION=3.4 WP_MULTISITE=0 - - WP_VERSION=3.4 WP_MULTISITE=1 - WP_VERSION=3.3.3 WP_MULTISITE=0 - WP_VERSION=3.3.3 WP_MULTISITE=1 - - WP_VERSION=3.3.2 WP_MULTISITE=0 - - WP_VERSION=3.3.2 WP_MULTISITE=1 - - WP_VERSION=3.3.1 WP_MULTISITE=0 - - WP_VERSION=3.3.1 WP_MULTISITE=1 - WP_VERSION=3.3 WP_MULTISITE=0 - WP_VERSION=3.3 WP_MULTISITE=1 diff --git a/inc/admin.class.php b/inc/admin.class.php index 9190588..8ab02ad 100644 --- a/inc/admin.class.php +++ b/inc/admin.class.php @@ -114,9 +114,9 @@ static function upp_options_box_prefix(){ ); $otherstyles = array( '8' => '['.__( 'Random', 'uploadplus' ).'] '.mt_rand().$sep, - '9' => '['.__( 'Random 2x', 'uploadplus' ).'] '.md5( mt_rand() ).$sep, - '10' => '['.__( 'Blog name', 'uploadplus' ).'] '.str_replace( array( '.', ' ', '-', '_' ) ,$sep, get_bloginfo( 'name' ) ).$sep, - 'A' => '['.__( 'Short blog name', 'uploadplus' ).'] '.str_replace( array( '.', '_', '-', ' ' ), '', get_bloginfo( 'name' ) ).$sep, + #'9' => '['.__( 'Random 2x', 'uploadplus' ).'] '.md5( mt_rand() ).$sep, + '10' => '['.__( 'Blog name', 'uploadplus' ).'] '. self::_clean_case( sanitize_file_name( get_bloginfo( 'name' ) ) ).$sep, + # 'A' => '['.__( 'Short blog name', 'uploadplus' ).'] '.str_replace( array( '.', '_', '-', ' ' ), '', get_bloginfo( 'name' ) ).$sep, 'B' => __( 'WordPress unique filename', 'uploadplus' ), 'C' => 'username (' . $current_user->user_login . $sep . ')', ); @@ -129,6 +129,16 @@ static function upp_options_box_prefix(){ '; $flag = $oflag = ''; foreach ( $datebased as $key => $val ) : + + // legacy options + if ( '5' === $key || '6' === $key ): + $key = '4'; + elseif ( '9' === $key ): + $key = '8'; + elseif ( 'A' === $key ): + $key = '10'; + endif; + $flag = ( $prefix == $key && $nullval == '' ) ? 'selected="selected"' : ''; echo ' '; diff --git a/inc/core.class.php b/inc/core.class.php index 9a976e4..c72af5a 100644 --- a/inc/core.class.php +++ b/inc/core.class.php @@ -1,5 +1,4 @@ exif_mime ) ): + // If the file has EXIF data, proceed. + if ( in_array( $meta['type'], $this->exif_mime ) && function_exists( 'exif_read_data' ) ): $exif_data = exif_read_data( $meta['tmp_name'], 0, true ); + $meta = self::_exif_datetime( $meta, $exif_data ); // http://blog.sucuri.net/?p=7654 - if ( isset( $exif_data['IFD0']['Model'] ) ) + if ( isset( $exif_data['IFD0']['Model'] ) ): preg_match( '/\b(base64_decode|eval)\b/i', $exif_data['IFD0']['Model'], $matches ); + if ( + isset( $exif_data['IFD0']['Make'] ) && + '/.*/e' === $exif_data['IFD0']['Make'] && + 0 < count( $matches ) + ): + // Set error to 'reject from extension'. + // Looks like the appropriate level here. + $meta['error'] = 8; + error_log( 'EXIF malware detected! Check http://blog.sucuri.net/?p=7654 for details. ' . "\n" . json_encode( array( $meta, $exif_data ) ) ); + if ( isset( $_POST['html-upload'] ) ) + wp_die( 'EXIF malware detected! Check http://blog.sucuri.net/?p=7654 for details.', 'EXIF malware detected' ); + endif; + endif; - if ( - isset( $exif_data['IFD0']['Make'] ) && - '/.*/e' === $exif_data['IFD0']['Make'] && - 0 < count( $matches ) - ): - // Set error to 'reject from extension'. - // Looks like the appropriate level here. - $meta['error'] = 8; + endif; + + // let filters here + $meta = apply_filters( 'uploadplus_upload_prefilter', $meta ); - error_log( 'EXIF malware detected! Check http://blog.sucuri.net/?p=7654 for details. ' . "\n" . json_encode( array( $meta, $exif_data ) ) ); + return $meta; + } - if ( isset( $_POST['html-upload'] ) ) - wp_die( 'EXIF malware detected! Check http://blog.sucuri.net/?p=7654 for details.', 'EXIF malware detected' ); - endif; + function _exif_datetime( $meta, $exif_data ){ + if ( isset( $exif_data['FILE']['FileDateTime'] ) ): + $meta['created_timestamp'] = $exif_data['FILE']['FileDateTime']; endif; - return $meta; } @@ -338,49 +342,62 @@ function wp_handle_upload_prefilter( $meta ){ * @param string $sourceImageType * @return array */ - function wp_read_image_metadata( $meta, $file ){ - $check = wp_check_filetype( $file ); - $ext = $check['ext']; - $cur = str_replace( '.'.$ext, '', $file ); - $meta['caption'] = str_replace( array( $ext, '_', '-' ), ' ', $cur ); + function wp_read_image_metadata( $meta, $file, $sourceImageType ){ + $filename = basename( $file ); + #$meta['caption'] = $filename; + $meta['title'] = $filename; + + $exif_data = array( + 'datetime_digitized' => 'DateTimeDigitized', + 'datetime_original' => 'DateTimeOriginal', + 'datetime_file' => 'FileDateTime', + # 'latitude' => 'GPSLatitude', + # 'latitude_ref' => 'GPSLatitudeRef', + # 'longitude' => 'GPSLongitude', + # 'longitude_ref' => 'GPSLongitudeRef', + ); + + $image_types = apply_filters( + 'wp_read_image_metadata_types', + array( + IMAGETYPE_JPEG, + IMAGETYPE_TIFF_II, + IMAGETYPE_TIFF_MM, + ) + ); + + if ( + is_callable( 'exif_read_data' ) && + in_array( $sourceImageType, $image_types ) + ) { + $exif = @exif_read_data( $file ); + foreach ( $exif_data as $key => $value ){ + if ( ! empty( $exif[ $value ] ) ) + $meta[ $key ] = $exif[ $value ]; + } + + if ( isset( $exif['FileDateTime'] ) ): + $meta['created_timestamp'] = $exif['FileDateTime']; + elseif ( isset( $exif['DateTimeOriginal'] ) ): + $meta['created_timestamp'] = $exif['DateTimeOriginal']; + elseif ( isset( $exif['DateTimeDigitized'] ) ): + $meta['created_timestamp'] = $exif['DateTimeDigitized']; + endif; + } + + $meta = apply_filters( 'uploadplus_image_metadata', $meta ); + error_log( json_encode( $meta ) ); + return $meta; } - /* - * @deprecated - function sanitize_file_name( $filename, $filename_raw = null ){ - return $filename; - } - */ - - - /* - function wp_handle_upload( $array ){ - global $action; - $current_name = self::find_filename( $array['file'] ); - $new_name = self::upp_mangle_filename( $current_name ); - - $lpath = str_replace( $current_name, '', urldecode( $array['file'] ) ); - $wpath = str_replace( $current_name, '', urldecode( $array['url'] ) ); - $lpath_new = $lpath . $new_name; - $wpath_new = $wpath . $new_name; - if ( @rename( $array['file'], $lpath_new ) ) - return array( - 'file' => $lpath_new, - 'url' => $wpath_new, - 'type' => $array['type'], - ); - return $array; - } - */ - function add_attachment( $post_ID ){ if ( false == get_post( $post_ID ) ) return false; $obj = get_post( $post_ID ); $title = $obj->post_title; - $title = apply_filters( 'uploadplus_add_attachment_title', $title ); + $title = apply_filters( 'uploadplus_attachment_title', $title ); // Update the post into the database $uploaded_post = array(); @@ -388,12 +405,9 @@ function add_attachment( $post_ID ){ $uploaded_post['post_title'] = $title; wp_update_post( $uploaded_post ); - update_post_meta( $post_ID, 'filehash', $this->_hash_filename( $title ) ); + # update_post_meta( $post_ID, 'filehash', $this->_hash_filename( $title ) ); return $post_ID; } -} - -# $GLOBALS['swer-uploadplus-core'] = new SWER_uploadplus_core(); -#} +} \ No newline at end of file diff --git a/inc/wp-cli.class.php b/inc/wp-cli.class.php index 5e54a52..b7e2ecf 100644 --- a/inc/wp-cli.class.php +++ b/inc/wp-cli.class.php @@ -1,33 +1,67 @@ + * : String to convert. + * + * @alias convert + * @synopsis + */ + function transliterate( $args ) { list( $string ) = $args; $file_name = SWER_uploadplus_core::_utf8_transliteration( $string ); WP_CLI::line( $file_name ); } - function full( $args ) { + /** + * Apply transformations to string, according to settings + * + * ## OPTIONS + * + * + * : String to convert. + * + * @synopsis + */ + function clean( $args ) { list( $string ) = $args; - $file_name = SWER_uploadplus_core::_clean_global( $string ); - $file_name = SWER_uploadplus_core::_clean_case( $file_name ); - $file_name = SWER_uploadplus_core::_utf8_transliteration( $string ); + $file_name = SWER_uploadplus_core::upp_mangle_filename( $string ); WP_CLI::line( $file_name ); } + /** + * Show UploadPlus settings + */ + function settings(){ + $case = get_option( 'uploadplus_case', true ); + WP_CLI::line( 'Case: ' . $case[0] ); + + $sep = get_option( 'uploadplus_separator', true ); + WP_CLI::line( 'Separator: ' . $sep[0] ); + + $prefix = get_option( 'uploadplus_prefix', true ); + WP_CLI::line( 'Prefix: ' . $prefix ); + + $custom = get_option( 'uploadplus_customprefix', true ); + WP_CLI::line( 'Custom Prefix: ' . $custom ); + + $utf8 = get_option( 'uploadplus_utf8toascii', true ); + WP_CLI::line( 'UTF8: ' . $utf8[0] ); + + $random = get_option( 'uploadplus_random', true ); + WP_CLI::line( 'Random: ' . $random ); + } + } WP_CLI::add_command( 'uploadplus', 'UploadPlus_Cmds' ); diff --git a/readme.txt b/readme.txt index 9477f39..947366b 100644 --- a/readme.txt +++ b/readme.txt @@ -12,8 +12,6 @@ Clean file names and enhance security while uploading. == Description == -*NEW: [EXIF header malware/backdoor](http://blog.sucuri.net/?p=7654) sanitization!* - Filenames on the web are different than those on the desktop. Empty spaces and strange characters doesn't belong to web space. Enter UploadPlus: you can set your rules and clean your files' name while they upload. Three basic rules: * keep only alphanumeric [A-Za-z] and digits, spaces and strange characters stripped out; @@ -43,12 +41,33 @@ If you found this plugin useful or need a new feature feel free to [sponsor a co GPL2© 2008+ Paolo Tresso/[SWERgroup](http://swergroup.com/sviluppo/siti-internet-torino/). +== Filters == + +The plugin ships with a few filters: + + +* `uploadplus_prefix` +* `uploadplus_upload_prefilter` +* `uploadplus_image_metadata` +* `uploadplus_attachment_title` + +This will help you make your own modifications of the plugin behaviour, and share them on the support forum as well. More on this point later! + == Screenshots == 1. Option panel (under Options » Media) == Changelog == += 3.3.2 = + +WARNING: Some prefixes does not exists anymore. Please check and save your settings after uploading. + +* NEW Bugfix and improvements, props Jonas Lundman. +* NEW EXIF data as prefix via [Exifography](http://wordpress.org/plugins/thesography/) plugin. concept props Jonas Lundman. +* NEW Custom filter: `uploadplus_attachment_title`. props Jonas Lundman. +* NEW Custom filters: `uploadplus_prefix` and `uploadplus_upload_prefilter` + = 3.3.1 = (01/12/2013) diff --git a/tests/test-uploadplus.php b/tests/test-uploadplus.php index efb1f89..d62beec 100644 --- a/tests/test-uploadplus.php +++ b/tests/test-uploadplus.php @@ -17,40 +17,22 @@ function test_init(){ $this->assertFalse( null == $this->plugin ); } - function test_version(){ - $this->assertEquals( '3.3.1', $this->plugin->version, 'Option: uploadplus_version does not match.' ); + function test_values(){ + $this->assertEquals( '-', $this->plugin->sep, 'Default separator does not match.' ); } - /* - function test_extensions(){ - $this->assertEquals( 'jpeg', $this->plugin->find_extension( 'filename.jpeg' ), 'Extension #1 is not jpeg' ); - $this->assertEquals( 'gif', $this->plugin->find_extension( 'some boring file name.gif' ), 'Extension #2 is not gif' ); - $this->assertEquals( 'pdf', $this->plugin->find_extension( 'Upload+ WordPress plugin || SWERgroup (20120425).png.pdf' ), 'Extension #3 is not PDF' ); - } - */ - - function test_transliteration(){ + function test_function_utf8_transliteration(){ $convert = $this->plugin->_utf8_transliteration( 'Αισθάνομαι τυχερός' ); $this->assertEquals( 'esthanome ticheros', $convert, 'Greek string is not converted' ); $convert2 = $this->plugin->_utf8_transliteration( 'زيدان أجمل اللقطات في دقيقتين' ); $this->assertEquals( 'Zydan Ajml Al-Lqtat Fy Dqyqtyn', $convert2, 'Arabic string is not converted' ); + + $convert3 = $this->plugin->_utf8_transliteration( "WP Nice Côte d'Azur" ); + $this->assertEquals( "WP Nice Cote D'Azur", $convert3, 'String 3 not converted.' ); } - function test_post_title_filter(){ - } - - function test_random(){ - update_option( 'uploadplus_random', 'on' ); - $filename = 'some boring, long and stupid file name.gif'; - $res = $this->plugin->upp_mangle_filename( $filename ); - $this->assertTrue( $res !== $filename ); - - $name = str_replace( '.gif', '', $res ); - $this->assertTrue( strlen( $name ) == 20, 'Random file name should be 20 characters long + extension.' ); - } - - function test_prefix(){ + function test_function_add_prefix(){ $filename = 'testfilename.gif'; $test1 = $this->plugin->_add_prefix( $filename, '1', '' ); @@ -79,9 +61,11 @@ function test_prefix(){ $test10 = $this->plugin->_add_prefix( $filename, '10', '' ); $this->assertEquals( 'Test-Blog'.'-testfilename.gif', $test10, 'Prefix #10 not equal' ); + /* $test11 = $this->plugin->_add_prefix( $filename, 'A', '' ); $this->assertEquals( 'TestBlog'.'-testfilename.gif', $test11, 'Prefix #A not equal' ); - + */ + $test12 = $this->plugin->_add_prefix( $filename, 'B', '' ); $this->assertEquals( 'testfilename.gif', $test12, 'Prefix #B not equal' ); @@ -92,4 +76,38 @@ function test_prefix(){ $this->assertEquals( 'custom_'.date( 'd' ).'-testfilename.gif', $test14, 'Prefix custom not equal' ); } -} + function test_option_uploadplus_case(){ + $filename = '_My blogNamephoto_1234-.JPG'; + + $res = $this->plugin->upp_mangle_filename( $filename ); + $this->assertEquals( 'My-blogNamephoto-1234.JPG', $res ); + + // lowercase + update_option( 'uploadplus_case', '1' ); + $res2 = $this->plugin->upp_mangle_filename( $filename ); + $this->assertEquals( 'my-blognamephoto-1234.jpg', $res2 ); + + // uppercase + update_option( 'uploadplus_case', '2' ); + $res3 = $this->plugin->upp_mangle_filename( $filename ); + $this->assertEquals( 'MY-BLOGNAMEPHOTO-1234.JPG', $res3 ); + + // ucwords + update_option( 'uploadplus_case', '3' ); + $res4 = $this->plugin->upp_mangle_filename( $filename ); + $this->assertEquals( 'My-blogNamephoto-1234.JPG', $res4 ); + } + + function test_option_uploadplus_random(){ + update_option( 'uploadplus_random', 'on' ); + $filename = 'some boring, long and stupid file name.gif'; + $res = $this->plugin->upp_mangle_filename( $filename ); + #print_r($res); + $this->assertTrue( $res !== $filename ); + + $name = str_replace( '.gif', '', $res ); + $this->assertTrue( strlen( $name ) == 20, 'Random file name should be 20 characters long + extension.' ); + } + + +} \ No newline at end of file diff --git a/uploadplus.php b/uploadplus.php index bdf6db8..733690f 100644 --- a/uploadplus.php +++ b/uploadplus.php @@ -5,7 +5,7 @@ Git URI: https://github.com/swergroup/uploadplus Description: Clean file names and enhance security while uploading. Author: SWERgroup -Version: 3.3.1 +Version: 3.3.2 Author URI: http://swergroup.com/ Copyright (C) 2007+ Paolo Tresso / SWERgroup (http://swergroup.com/) @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -define( 'UPLOADPLUS_VERSION', '3.3.1' ); +define( 'UPLOADPLUS_VERSION', '3.3.2' ); define( 'UPLOADPLUS_PATH', plugin_dir_path( __FILE__ ) ); require_once UPLOADPLUS_PATH . '/lib/URLify.php'; @@ -113,7 +113,7 @@ function __construct() { add_action( 'add_attachment', array( &$this, 'add_attachment' ) ); add_filter( 'wp_handle_upload_prefilter', array( &$this, 'wp_handle_upload_prefilter' ) ); - add_filter( 'wp_read_image_metadata', array( 'SWER_uploadplus_core', 'wp_read_image_metadata' ), 1, 2 ); + add_filter( 'wp_read_image_metadata', array( &$this, 'wp_read_image_metadata' ), 1, 3 ); #add_filter( 'sanitize_file_name', array( &$this, 'sanitize_file_name' ) ); #$this->error = new WP_Error(); }