provider_object ); $fixed = $item->provider_object !== $provider_object; $provider_object = AS3CF_Utils::maybe_unserialize( $provider_object ); if ( false === $provider_object ) { AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object ); $this->error_count++; return false; } if ( $fixed ) { if ( update_post_meta( $item->ID, 'amazonS3_info', $provider_object ) ) { $msg = sprintf( __( 'Fixed legacy amazonS3_info metadata when updating file size metadata, please check bucket and path for attachment ID %1$s', 'amazon-s3-and-cloudfront' ), $item->ID ); AS3CF_Error::log( $msg ); } else { AS3CF_Error::log( 'Failed to fix broken serialized legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object ); $this->error_count++; return false; } } // Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values. $as3cf_item = Media_Library_Item::get_by_source_id( $item->ID ); if ( ! $as3cf_item ) { AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' ); $this->error_count++; return false; } // $as3cf_item can't exist without a region value, so we can just use it here. $region = $as3cf_item->region(); $provider_client = $this->as3cf->get_provider_client( $region, true ); $main_file = $provider_object['key']; $ext = pathinfo( $main_file, PATHINFO_EXTENSION ); $prefix = trailingslashit( dirname( $provider_object['key'] ) ); // Used to search S3 for all files related to an attachment $search_prefix = $prefix . wp_basename( $main_file, ".$ext" ); $args = array( 'Bucket' => $provider_object['bucket'], 'Prefix' => $search_prefix, ); try { // List objects for the attachment $result = $provider_client->list_objects( $args ); } catch ( Exception $e ) { AS3CF_Error::log( 'Error listing objects of prefix ' . $search_prefix . ' for attachment ' . $item->ID . ' in bucket: ' . $e->getMessage() ); $this->error_count++; return false; } $file_size_total = 0; $main_file_size = 0; if ( ! empty( $result['Contents'] ) ) { foreach ( $result['Contents'] as $object ) { if ( ! isset( $object['Size'] ) ) { continue; } $size = $object['Size']; // Increment the total size of files for the attachment $file_size_total += $size; if ( $object['Key'] === $main_file ) { // Record the size of the main file $main_file_size = $size; } } } if ( 0 === $file_size_total ) { AS3CF_Error::log( 'Total file size for the attachment is 0: ' . $item->ID ); $this->error_count++; return false; } // Update the main file size for the attachment $meta = get_post_meta( $item->ID, '_wp_attachment_metadata', true ); $meta['filesize'] = $main_file_size; update_post_meta( $item->ID, '_wp_attachment_metadata', $meta ); // Add the total file size for all image sizes update_post_meta( $item->ID, 'wpos3_filesize_total', $file_size_total ); return true; } /** * Get all attachments removed from the server. * * @param string $prefix * @param int $limit * @param bool|mixed $offset * * @return array */ protected function get_items_to_process( $prefix, $limit, $offset = false ) { $all_attachments = $this->get_provider_attachments( $prefix, $limit ); $attachments = array(); foreach ( $all_attachments as $attachment ) { if ( ! file_exists( get_attached_file( $attachment->ID, true ) ) ) { $attachments[] = $attachment; } } return $attachments; } /** * Wrapper for database call to get attachments uploaded to S3, * that don't have the file size meta added already * * @param string $prefix * @param null|int $limit * * @return mixed */ protected function get_provider_attachments( $prefix, $limit = null ) { global $wpdb; $sql = "SELECT pm1.`post_id` as `ID`, pm1.`meta_value` AS 'provider_object' FROM `{$prefix}postmeta` pm1 LEFT OUTER JOIN `{$prefix}postmeta` pm2 ON pm1.`post_id` = pm2.`post_id` AND pm2.`meta_key` = 'wpos3_filesize_total' WHERE pm1.`meta_key` = 'amazonS3_info' AND pm2.`post_id` is null"; if ( $limit && $limit > 0 ) { $sql .= sprintf( ' LIMIT %d', (int) $limit ); } return $wpdb->get_results( $sql, OBJECT ); } }