Commit ae0a6acc authored by Joe Hoyle's avatar Joe Hoyle
Browse files

Use streams instead for uploading etc

parent 80f1fc7e
Loading
Loading
Loading
Loading
+6 −46
Original line number Diff line number Diff line
@@ -2,9 +2,9 @@

class S3_Uploads_Uploader {

	private $bucket;
	private $key;
	private $secret;
	protected $bucket;
	protected $key;
	protected $secret;

	/**
	 * @param string $bucket 
@@ -15,55 +15,15 @@ class S3_Uploads_Uploader {
		$this->bucket = $bucket;
		$this->key = $key;
		$this->secret = $secret;

		$this->s3()->registerStreamWrapper();
		stream_context_set_option( stream_context_get_default(), 's3', 'ACL', Aws\S3\Enum\CannedAcl::PUBLIC_READ );
	}

	public function get_s3_url() {
		return 'https://' . $this->bucket . '.s3.amazonaws.com';
	}

	/**
	 * Upload a file to S3
	 * 
	 * @param string $file_path The file system path
	 * @return string The path to the uploaded file
	 */
	public function upload_file_to_s3( $file_path ) {

		$relative = str_replace( WP_CONTENT_DIR . '/', '', $file_path );

		try {
			$this->s3()->putObject(array(
				'Bucket' => $this->bucket,
				'Key'    => $relative,
				'Body'   => fopen( $file_path, 'r' ),
				'ACL'	=> Aws\S3\Enum\CannedAcl::PUBLIC_READ
			));
		} catch( Exception $e ) {
			return new WP_Error( 's3-upload-error', $e->getMessage() );
		}
		return $relative;
	}

	/**
	 * Delete a file from S3
	 * 
	 * @param string $file_path s3 path to file
	 * @return bool|WP_Error
	 */
	public function delete_file_from_s3( $file_path ) {

		try {
			$this->s3()->deleteObject( array(
				"Bucket" => $this->bucket,
				"Key" => $file_path
			));
		} catch( Exception $e ) {
			return new WP_Error( 's3-delete-error' );
		}

		return true;
	}

	/**
	 * @return Aws\S3\S3Client
	 */
+35 −89
Original line number Diff line number Diff line
@@ -9,123 +9,69 @@ class S3_Uploads_WordPress_Uploads_Uploader extends S3_Uploads_Uploader {
	public function __construct( $bucket, $key, $secret ) {

		parent::__construct( $bucket, $key, $secret );
		add_filter( 'wp_update_attachment_metadata', array( $this, 'filter_upload_images' ), 10, 2 );
		add_filter( 'update_attached_file', array( $this, 'filter_upload_attachment' ), 10, 2 );
		add_filter( 'wp_get_attachment_url', array( $this, 'filter_get_attachment_url' ), 9, 2 );
		add_action( 'delete_attachment', array( $this, 'filter_delete_attachment' ) );
		add_filter( 'get_attached_file', array( $this, 'filter_get_attachment_url' ), 10, 2 );
	}
		add_filter( 'get_attached_file', array( $this, 'filter_get_attached_file' ), 10, 2 );

	/**
	 * Upload an image to S3 when it's uploaded to WP
	 */
	public function filter_upload_images( $file, $attachment_id ) {

		if ( empty( $file ) )
			return $file;
		add_filter( 'wp_handle_upload', array( $this, 'filter_wp_handle_upload' ) );
		add_filter( 'load_image_to_edit_path', array( $this, 'filter_load_image_to_edit_path' ) );

		$original_file = get_attached_file( $attachment_id, true );
	}

		foreach ( $file['sizes'] as $size => $image ) {
			$thumbnail = dirname( $original_file ) . '/' . $image['file'];
	public function filter_wp_handle_upload( $file ) {

			if ( ! file_exists( $thumbnail ) )
				continue;
		$path = str_replace( WP_CONTENT_DIR . '/', '', $file['file'] );
		$new_file = 's3://' . $this->bucket . '/' . $path;
		copy( $file['file'], $new_file );
		unlink( $file['file'] );

			$response = $this->upload_file_to_s3( $thumbnail );
			if ( is_wp_error( $response ) ) {
				echo '<div class="error-div">
					<a class="dismiss" href="#" onclick="jQuery(this).parents(\'div.media-item\').slideUp(200, function(){jQuery(this).remove();});">' . __( 'Dismiss' ) . '</a>
					<strong>' . sprintf(__('&#8220;%s&#8221; has failed to upload due to an error'), esc_html( $_FILES['async-upload']['name'] ) ) . '</strong><br />' .
					esc_html( $response->get_error_message() ) . '</div>';
			}
		$file['file'] = $new_file;
		$file['url'] = $this->get_s3_url() . '/' . $path;

			unlink( $thumbnail );
		return $file;
	}

		unlink( $original_file );
	public function filter_load_image_to_edit_path( $url ) {

		return $file;
		return $this->get_s3_path_for_public_url( $url );
	}

	/**
	 * Upload an attachment to S3 when it's uploaded to WP
	 * 
	 * @param string $file
	 * @param int    $attachment_id
	 * Replace the saved attachment URL with the bucket URL
	 */
	public function filter_upload_attachment( $file, $attachment_id ) {

		if ( ! file_exists( $file ) || strpos( $file, WP_CONTENT_DIR ) !== 0 )
			return $file;

		$relative = str_replace( WP_CONTENT_DIR . '/', '', $file );
	public function filter_get_attachment_url( $url, $attachment_id ) {

		$response = wp_remote_head( $this->get_s3_url() .'/'. $relative );
		$path = get_post_meta( $attachment_id, '_wp_attached_file', true );

		if ( wp_remote_retrieve_response_code( $response ) == 200 ) {
			wp_delete_attachment( $attachment_id, true );
		if ( strpos( $path, 's3://' ) !== 0 )
			return $url;

			unlink( $file );
		preg_match( '#s3://.+?/(.+)#', $path, $matches );

			echo '<div class="error-div">
					<a class="dismiss" href="#" onclick="jQuery(this).parents(\'div.media-item\').slideUp(200, function(){jQuery(this).remove();});">' . __( 'Dismiss' ) . '</a>
					<strong>' . sprintf(__('&#8220;%s&#8221; has failed to upload due to an error'), esc_html($_FILES['async-upload']['name']) ) . '</strong><br />' .
					esc_html( 'Duplicate file name' ) . '</div>';
			exit;            
		return $this->get_s3_url() . '/' . $matches[1];
	}

		$uploaded_file = $this->upload_file_to_s3( $file );
	public function filter_get_attached_file( $path, $id ) {

		if ( is_wp_error( $uploaded_file ) ) {

			wp_delete_attachment( $attachment_id, true );
			unlink( $file );
			
			echo '<div class="error-div">
					<a class="dismiss" href="#" onclick="jQuery(this).parents(\'div.media-item\').slideUp(200, function(){jQuery(this).remove();});">' . __( 'Dismiss' ) . '</a>
					<strong>' . sprintf(__('&#8220;%s&#8221; has failed to upload due to an error'), esc_html( $_FILES['async-upload']['name'] ) ) . '</strong><br />' .
					esc_html( $uploaded_file->get_error_message() ) . '</div>';
			exit;
		if ( strpos( $path, 's3://' ) ) {
			return get_post_meta( $id, '_wp_attached_file', true );
		}

		update_post_meta( $attachment_id, 's3_path', $relative );
		unlink( $file );

		return $file;
		return $path;
	}

	/**
	 * Replace the saved attachment URL with the bucket URL
	 */
	public function filter_get_attachment_url( $url, $attachment_id ) {
		
		if ( ! $path = get_post_meta( $attachment_id, 's3_path', true ) )
			return $url;

		return $this->get_s3_url() . '/' . $path;
	public function is_attachment_uploaded( $attachment_id ) {
		return (bool) get_post_meta( $attachment_id, 's3_path', true );
	}

	/**
	 * Delete the attachment on S3 when it's deleted locally
	 */
	public function filter_delete_attachment( $attachment_id ) {

		$meta = wp_get_attachment_metadata( $attachment_id );
		$file = get_attached_file( $attachment_id, true );
	private function get_public_url_for_s3_path( $s3_path ) {

		$this->delete_file_from_s3( $file );
		preg_match( '#s3://.+?/(.+)#', $path, $matches );

		if ( isset( $meta['sizes'] ) ) {
			foreach ( $meta['sizes'] as $size => $image ) {

				$thumbnail = dirname( $file ) . '/' . $image['file'];
				$this->delete_file_from_s3( $thumbnail );
			}
		}
		return $this->get_s3_url() . '/' . $matches[1];
	}

	public function is_attachment_uploaded( $attachment_id ) {
		return (bool) get_post_meta( $attachment_id, 's3_path', true );
	private function get_s3_path_for_public_url( $url ) {

		return str_replace( $this->get_s3_url(), 's3://' . $this->bucket, $url );
	}
}