Changeset 2640
- Timestamp:
- 02/26/2016 07:52:43 AM (9 years ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
r2625 r2640 328 328 * @return \WP_Post|\WP_Error 329 329 */ 330 public function get_plugin_post( $plugin_slug ) {330 static public function get_plugin_post( $plugin_slug ) { 331 331 if ( $plugin_slug instanceof \WP_Post ) { 332 332 return $plugin_slug; … … 337 337 'post_type' => 'plugin', 338 338 'name' => $plugin_slug, 339 'post_status' => 'any',339 'post_status' => array( 'publish', 'pending', 'disabled', 'closed' ), 340 340 ) ); 341 341 if ( ! $posts ) { … … 360 360 * @return \WP_Post|\WP_Error 361 361 */ 362 public function create_plugin_post( array $plugin_info ) {362 static public function create_plugin_post( array $plugin_info ) { 363 363 $title = !empty( $plugin_info['title'] ) ? $plugin_info['title'] : ''; 364 364 $slug = !empty( $plugin_info['slug'] ) ? $plugin_info['slug'] : sanitize_title( $title ); -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-upload-handler.php
r2625 r2640 1 1 <?php 2 2 namespace WordPressdotorg\Plugin_Directory\Shortcodes; 3 use WordPressdotorg\Plugin_Directory\Plugin_Directory; 4 use WordPressdotorg\Plugin_Directory\Tools\Filesystem; 3 5 4 6 /** … … 10 12 11 13 /** 12 * Path to `rm` script.14 * Path to temporary plugin folder. 13 15 * 14 16 * @var string 15 17 */ 16 const RM = '/bin/rm';17 18 /** 19 * Path to `unzip` script.18 protected $plugin_dir; 19 20 /** 21 * Path to the detected plugins files. 20 22 * 21 23 * @var string 22 24 */ 23 const UNZIP = '/usr/bin/unzip'; 24 25 /** 26 * Path to temporary directory. 25 protected $plugin_root; 26 27 /** 28 * The uploaded plugin headers. 29 * 30 * @var array 31 */ 32 protected $plugin; 33 34 /** 35 * The plugin slug. 27 36 * 28 37 * @var string 29 38 */ 30 protected $tmp_dir;31 32 /**33 * Path to temporary plugin folder.34 *35 * @var string36 */37 protected $plugin_dir;38 39 /**40 * The uploaded plugin.41 *42 * @var array43 */44 protected $plugin;45 46 /**47 * The plugin slug.48 *49 * @var string50 */51 39 protected $plugin_slug; 52 53 /**54 * The plugin post if it already exists in the repository.55 *56 * @var \WP_Post57 */58 protected $plugin_post;59 60 /**61 * The plugin author (current user).62 *63 * @var \WP_User64 */65 protected $author;66 40 67 41 /** … … 73 47 require_once( ABSPATH . 'wp-admin/includes/file.php' ); 74 48 require_once( ABSPATH . 'wp-admin/includes/media.php' ); 75 76 $this->create_tmp_dirs();77 $this->unwrap_package();78 79 add_filter( 'extra_plugin_headers', array( $this, 'extra_plugin_headers' ) );80 49 } 81 50 … … 88 57 */ 89 58 public function process_upload() { 90 $plugin_files = $this->get_all_files( $this->plugin_dir ); 91 92 // First things first. Do we have something to work with? 93 if ( empty( $plugin_files ) ) { 94 return __( 'The zip file was empty.', 'wporg-plugins' ); 95 } 96 59 $zip_file = $_FILES['zip_file']['tmp_name']; 60 $this->plugin_dir = Filesystem::unzip( $zip_file ); 61 62 $plugin_files = Filesystem::list_files( $this->plugin_dir, true /* Recursive */, '!\.php$!i' ); 97 63 foreach ( $plugin_files as $plugin_file ) { 98 if ( ! is_readable( $plugin_file ) ) {99 continue;100 }101 102 64 $plugin_data = get_plugin_data( $plugin_file, false, false ); // No markup/translation needed. 103 65 if ( ! empty( $plugin_data['Name'] ) ) { 104 66 $this->plugin = $plugin_data; 67 $this->plugin_root = dirname( $plugin_file ); 105 68 break; 106 69 } … … 108 71 109 72 // Let's check some plugin headers, shall we? 110 111 if ( ! $this->plugin['Name']) {112 $error = __( 'The plugin has no name.', 'wporg-plugins' ) . ' ';73 // Catches both empty Plugin Name & when no valid files could be found. 74 if ( empty( $this->plugin['Name'] ) ) { 75 $error = __( 'The plugin has no name.', 'wporg-plugins' ); 113 76 114 77 /* translators: 1: comment header line, 2: Codex URL */ 115 $error .=sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%2$s">Plugin Headers</a>', 'wporg-plugins' ),78 return $error . ' ' . sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%2$s">Plugin Headers</a>', 'wporg-plugins' ), 116 79 '<code>Plugin Name:</code>', 117 80 __( 'https://codex.wordpress.org/File_Header', 'wporg-plugins' ) 118 81 ); 119 120 return $error;121 82 } 122 83 123 84 // Determine the plugin slug based on the name of the plugin in the main plugin file. 124 85 $this->plugin_slug = sanitize_title_with_dashes( $this->plugin['Name'] ); 125 $this->author = wp_get_current_user();126 86 127 87 // Make sure it doesn't use a slug deemed not to be used by the public. 128 88 if ( $this->has_reserved_slug() ) { 129 89 /* translators: 1: plugin slug, 2: style.css */ 130 return sprintf( __( 'Sorry, the plugin name %1$s is reserved for use by WordPress Core. Please change the name of your plugin and upload it again.', 'wporg-plugins' ),90 return sprintf( __( 'Sorry, the plugin name %1$s is reserved for use by WordPress. Please change the name of your plugin and upload it again.', 'wporg-plugins' ), 131 91 '<code>' . $this->plugin_slug . '</code>' 132 92 ); 133 93 } 134 94 135 // Populate the plugin post and author.136 $this->plugin_post = $this->get_plugin_post();137 138 95 // Is there already a plugin with the name name? 139 if ( ! empty( $this->plugin_post) ) {96 if ( Plugin_Directory::get_plugin_post( $this->plugin_slug ) ) { 140 97 /* translators: 1: plugin slug, 2: style.css */ 141 98 return sprintf( __( 'There is already a plugin called %1$s by a different author. Please change the name of your plugin and upload it again.', 'wporg-plugins' ), … … 144 101 } 145 102 146 $plugin_description = $this->strip_non_utf8( (string) $this->plugin['Description'] ); 147 if ( empty( $plugin_description ) ) { 148 $error = __( 'The plugin has no description.', 'wporg-plugins' ) . ' '; 103 if ( ! $this->plugin['Description'] ) { 104 $error = __( 'The plugin has no description.', 'wporg-plugins' ); 149 105 150 106 /* translators: 1: comment header line, 2: style.css, 3: Codex URL */ 151 $error .=sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%3$s">Plugin Headers</a>', 'wporg-plugins' ),107 return $error . ' ' . sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%3$s">Plugin Headers</a>', 'wporg-plugins' ), 152 108 '<code>Description:</code>', 153 109 __( 'https://codex.wordpress.org/File_Header', 'wporg-plugins' ) 154 110 ); 155 156 return $error;157 111 } 158 112 159 113 if ( ! $this->plugin['Version'] ) { 160 $error = __( 'The plugin has no version.', 'wporg-plugins' ) . ' ';114 $error = __( 'The plugin has no version.', 'wporg-plugins' ); 161 115 162 116 /* translators: 1: comment header line, 2: style.css, 3: Codex URL */ 163 $error .=sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%3$s">Plugin Headers</a>', 'wporg-plugins' ),117 return $error . ' ' . sprintf( __( 'Add a %1$s line to your main plugin file and upload the plugin again. <a href="%3$s">Plugin Headers</a>', 'wporg-plugins' ), 164 118 '<code>Version:</code>', 165 119 __( 'https://codex.wordpress.org/File_Header', 'wporg-plugins' ) 166 120 ); 167 168 return $error;169 121 } 170 122 … … 183 135 } 184 136 185 // Don't send special plugins through Plugin Check. 186 if ( ! has_category( 'special-case-plugin', $this->plugin_post ) ) { 187 // Pass it through Plugin Check and see how great this plugin really is. 188 $result = $this->check_plugin( $plugin_files ); 189 190 if ( ! $result ) { 191 /* translators: 1: Plugin Check Plugin URL, 2: make.wordpress.org/plugins */ 192 return sprintf( __( 'Your plugin has failed the plugin check. Please correct the problems with it and upload it again. You can also use the <a href="%1$s">Plugin Check Plugin</a> to test your plugin before uploading. If you have any questions about this please post them to %2$s.', 'wporg-plugins' ), 193 '//wordpress.org/plugins/plugin-check/', 194 '<a href="https://make.wordpress.org/plugins">https://make.wordpress.org/plugins</a>' 195 ); 196 } 137 // Pass it through Plugin Check and see how great this plugin really is. 138 $result = $this->check_plugin(); 139 140 if ( ! $result ) { 141 /* translators: 1: Plugin Check Plugin URL, 2: make.wordpress.org/plugins */ 142 return sprintf( __( 'Your plugin has failed the plugin check. Please correct the problems with it and upload it again. You can also use the <a href="%1$s">Plugin Check Plugin</a> to test your plugin before uploading. If you have any questions about this please post them to %2$s.', 'wporg-plugins' ), 143 '//wordpress.org/plugins/plugin-check/', 144 '<a href="https://make.wordpress.org/plugins">https://make.wordpress.org/plugins</a>' 145 ); 197 146 } 198 147 … … 201 150 202 151 // Add a Plugin Directory entry for this plugin. 203 $post_id = $this->create_plugin_post(); 204 205 $attachment = $this->save_zip_file( $post_id ); 152 $plugin_post = Plugin_Directory::create_plugin_post( array( 153 'title' => $this->plugin['Name'], 154 'slug' => $this->plugin_slug, 155 'status' => 'pending', 156 'author' => get_current_user_id(), 157 'description' => $this->plugin['Description'] 158 ) ); 159 if ( is_wp_error( $plugin_post ) ) { 160 return $plugin_post->get_error_message(); 161 } 162 163 $attachment = $this->save_zip_file( $plugin_post->ID ); 206 164 if ( is_wp_error( $attachment ) ) { 207 165 return $attachment->get_error_message(); … … 211 169 $this->send_email_notification(); 212 170 213 do_action( 'plugin_upload', $this->plugin, $ this->plugin_post );171 do_action( 'plugin_upload', $this->plugin, $plugin_post ); 214 172 215 173 // Success! 216 174 /* translators: 1: plugin name */ 217 218 175 return sprintf( __( 'Thank you for uploading %1$s to the WordPress Plugin Directory. We’ve sent you an email verifying that we’ve received it.', 'wporg-plugins' ), 219 $this->plugin['Name'] 220 ); 221 } 222 223 /** 224 * Creates a temporary directory, and the plugin dir within it. 225 */ 226 public function create_tmp_dirs() { 227 // Create a temporary directory if it doesn't exist yet. 228 $tmp = '/tmp/wporg-plugin-upload'; 229 if ( ! is_dir( $tmp ) ) { 230 mkdir( $tmp, 0777 ); 231 } 232 233 // Create file with unique file name. 234 $this->tmp_dir = tempnam( $tmp, 'WPORG_PLUGIN_' ); 235 236 // Remove that file. 237 unlink( $this->tmp_dir ); 238 239 // Create a directory with that unique name. 240 mkdir( $this->tmp_dir, 0777 ); 241 242 // Get a sanitized name for that plugin and create a directory for it. 243 $base_name = $this->get_sanitized_zip_name(); 244 $this->plugin_dir = "{$this->tmp_dir}/{$base_name}"; 245 mkdir( $this->plugin_dir, 0777 ); 246 247 // Make sure we clean up after ourselves. 248 add_action( 'shutdown', array( $this, 'remove_files' ) ); 249 } 250 251 /** 252 * Unzips the uploaded plugin and saves it in the temporary plugin dir. 253 */ 254 public function unwrap_package() { 255 $unzip = escapeshellarg( self::UNZIP ); 256 $zip_file = escapeshellarg( $_FILES['zip_file']['tmp_name'] ); 257 $plugin_dir = escapeshellarg( $this->plugin_dir ); 258 259 // Unzip it into the plugin directory. 260 exec( escapeshellcmd( "{$unzip} -DD {$zip_file} -d {$plugin_dir}" ) ); 261 262 // Fix any permissions issues with the files. Sets 755 on directories, 644 on files. 263 exec( escapeshellcmd( "chmod -R 755 {$plugin_dir}" ) ); 264 exec( escapeshellcmd( "find {$plugin_dir} -type f -print0" ) . ' | xargs -I% -0 chmod 644 %' ); 265 } 266 267 /** 268 * Adds plugin headers that are expected in the directory. 269 * 270 * @param array $headers Additional plugin headers. Default empty array. 271 * @return array 272 */ 273 public function extra_plugin_headers( $headers ) { 274 $headers['Tags'] = 'Tags'; 275 276 return $headers; 277 } 278 279 /** 280 * Returns the the plugin post if it already exists in the repository. 281 * 282 * @return \WP_Post|null 283 */ 284 public function get_plugin_post() { 285 $plugins = get_posts( array( 286 'name' => $this->plugin_slug, 287 'posts_per_page' => 1, 288 'post_type' => 'plugin', 289 'orderby' => 'ID', 290 /* 291 * Specify post stati so this query returns a result for draft plugins, even 292 * if the uploading user doesn't have have the permission to view drafts. 293 */ 294 'post_status' => array( 'publish', 'pending', 'draft', 'future', 'trash', 'suspend' ), 295 'suppress_filters' => false, 296 ) ); 297 298 return current( $plugins ); 176 esc_html( $this->plugin['Name'] ) 177 ); 299 178 } 300 179 301 180 /** 302 181 * Whether the uploaded plugin uses a reserved slug. 303 *304 * Passes if the author happens to be `wordpressdotorg`.305 182 * 306 183 * @return bool … … 320 197 ); 321 198 322 return in_array( $this->plugin_slug, $reserved_slugs ) && 'wordpressdotorg' !== $this->author->user_login;199 return in_array( $this->plugin_slug, $reserved_slugs ); 323 200 } 324 201 … … 326 203 * Sends a plugin through Plugin Check. 327 204 * 328 * @param array $files All plugin files to check.329 205 * @return bool Whether the plugin passed the checks. 330 206 */ 331 public function check_plugin( $files ) { 332 207 public function check_plugin() { 333 208 // Run the checks. 334 209 // @todo Include plugin checker. 210 // pass $this->plugin_root as the plugin root 335 211 $result = true; 336 212 337 213 // Display the errors. 338 $verdict = $result ? array( 'tc-pass', __( 'Pass', 'wporg-plugins' ) ) : array( 339 'tc-fail', 340 __( 'Fail', 'wporg-plugins' ) 341 ); 214 if ( $result ) { 215 $verdict = array( 'pc-pass', __( 'Pass', 'wporg-plugins' ) ); 216 } else { 217 $verdict = array( 'pc-fail', __( 'Fail', 'wporg-plugins' ) ); 218 } 219 342 220 echo '<h4>' . sprintf( __( 'Results of Automated Plugin Scanning: %s', 'wporg-plugins' ), vsprintf( '<span class="%1$s">%2$s</span>', $verdict ) ) . '</h4>'; 343 221 echo '<ul class="tc-result">' . 'Result' . '</ul>'; … … 348 226 349 227 /** 350 * Creates a plugin post.351 *352 * @return int|\WP_Error The post ID on success. The value 0 or WP_Error on failure.353 */354 public function create_plugin_post() {355 $upload_date = current_time( 'mysql' );356 357 return wp_insert_post( array(358 'post_author' => $this->author->ID,359 'post_title' => $this->plugin['Name'],360 'post_name' => $this->plugin_slug,361 'post_excerpt' => $this->plugin['Description'],362 'post_date' => $upload_date,363 'post_date_gmt' => $upload_date,364 'comment_status' => 'closed',365 'ping_status' => 'closed',366 'post_status' => 'pending',367 'post_type' => 'plugin',368 'tags_input' => $this->plugin['Tags'],369 ) );370 }371 372 /**373 228 * Saves zip file and attaches it to the plugin post. 374 229 * … … 377 232 */ 378 233 public function save_zip_file( $post_id ) { 379 $_FILES['zip_file']['name'] = wp_generate_password( 12 ) . '-' . $_FILES['zip_file']['name'];234 $_FILES['zip_file']['name'] = wp_generate_password( 12, false ) . '-' . $_FILES['zip_file']['name']; 380 235 381 236 add_filter( 'site_option_upload_filetypes', array( $this, 'whitelist_zip_files' ) ); … … 396 251 397 252 /* translators: %s: plugin name */ 398 $email_subject = sprintf( __( '[WordPress Plugins] New Plugin - %s', 'wporg-plugins' ),253 $email_subject = sprintf( __( '[WordPress.org Plugins] New Plugin - %s', 'wporg-plugins' ), 399 254 $this->plugin['Name'] 400 255 ); … … 409 264 ); 410 265 411 wp_mail( $this->author->user_email, $email_subject, $email_content, 'From: plugins@wordpress.org' ); 266 $user_email = wp_get_current_user()->user_email; 267 268 wp_mail( $user_email, $email_subject, $email_content, 'From: plugins@wordpress.org' ); 412 269 } 413 270 … … 415 272 416 273 /** 417 * Returns a sanitized version of the uploaded zip file name.418 *419 * @return string420 */421 public function get_sanitized_zip_name() {422 return preg_replace( '|\W|', '', strtolower( basename( $_FILES['zip_file']['name'], '.zip' ) ) );423 }424 425 /**426 * Returns all (usable) files of a given directory.427 *428 * @param string $dir Path to directory to search.429 *430 * @return array All files within the passed directory.431 */432 public function get_all_files( $dir ) {433 $files = array();434 $dir_iterator = new \RecursiveDirectoryIterator( $dir );435 $iterator = new \RecursiveIteratorIterator( $dir_iterator, \RecursiveIteratorIterator::SELF_FIRST );436 437 foreach ( $iterator as $file ) {438 // Only return files that are no directory references or Mac resource forks.439 if ( $file->isFile() && ! in_array( $file->getBasename(), array(440 '..',441 '.'442 ) ) && ! stristr( $file->getPathname(), '__MACOSX' )443 ) {444 array_push( $files, $file->getPathname() );445 }446 }447 448 return $files;449 }450 451 /**452 274 * Whitelist zip files to be allowed to be uploaded to the media library. 453 275 * 454 * @param string $site_exts Whitelisted file extentions. 455 * 456 * @return string Whitelisted file extentions. 457 */ 458 public function whitelist_zip_files( $site_exts ) { 459 $file_extenstions = explode( ' ', $site_exts ); 460 $file_extenstions[] = 'zip'; 461 462 return implode( ' ', array_unique( $file_extenstions ) ); 463 } 464 465 /** 466 * Deletes the temporary directory. 467 */ 468 public function remove_files() { 469 $rm = escapeshellarg( self::RM ); 470 $files = escapeshellarg( $this->tmp_dir ); 471 472 exec( escapeshellcmd( "{$rm} -rf {$files}" ) ); 473 } 474 475 /** 476 * Strips invalid UTF-8 characters. 477 * 478 * Non-UTF-8 characters in plugin descriptions will causes blank descriptions in plugins.trac. 479 * 480 * @param string $string The string to be converted. 481 * 482 * @return string The converted string. 483 */ 484 protected function strip_non_utf8( $string ) { 485 ini_set( 'mbstring.substitute_character', 'none' ); 486 487 return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' ); 488 } 276 * As we only want to accept *.zip uploads, we specifically exclude all other types here. 277 * 278 * @return string Whitelisted ZIP filetypes. 279 */ 280 public function whitelist_zip_files() { 281 return 'zip'; 282 } 283 489 284 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-upload.php
r2625 r2640 12 12 if ( ! empty( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'wporg-plugins-upload' ) && 'upload' === $_POST['action'] ) { 13 13 if ( UPLOAD_ERR_OK === $_FILES['zip_file']['error'] ) { 14 switch_to_blog( WPORG_PLUGIN_DIRECTORY_BLOGID );15 14 $uploader = new Upload_Handler; 16 15 $message = $uploader->process_upload(); 17 restore_current_blog();18 19 16 } else { 20 17 $message = __( 'Error in file upload.', 'wporg-plugins' ); … … 38 35 <?php else : ?> 39 36 <p><?php printf( __( 'Before you can upload a new plugin, <a href="%s">please log in</a>.', 'wporg-plugins' ), esc_url( 'https://login.wordpress.org/' ) ); ?> 40 < p>37 </p> 41 38 <?php endif; 42 39 }
Note: See TracChangeset
for help on using the changeset viewer.