Files
LiveCartaWP/html/wp-content/plugins/s3-uploads/inc/class-wp-cli-command.php

361 lines
8.8 KiB
PHP

<?php
namespace S3_Uploads;
use Aws\Command;
use Aws\S3\Transfer;
use Exception;
use WP_CLI;
class WP_CLI_Command extends \WP_CLI_Command {
/**
* Verifies the API keys entered will work for writing and deleting from S3.
*
* @subcommand verify
*/
public function verify_api_keys() : void {
// Verify first that we have the necessary access keys to connect to S3.
if ( ! $this->verify_s3_access_constants() ) {
return;
}
// Get S3 Upload instance.
Plugin::get_instance();
// Create a path in the base directory, with a random file name to avoid potentially overwriting existing data.
$upload_dir = wp_upload_dir();
$s3_path = $upload_dir['basedir'] . '/' . wp_rand() . '.txt';
// Attempt to copy the local Canola test file to the generated path on S3.
WP_CLI::print_value( 'Attempting to upload file ' . $s3_path );
$copy = copy(
dirname( dirname( __FILE__ ) ) . '/verify.txt',
$s3_path
);
// Check that the copy worked.
if ( ! $copy ) {
WP_CLI::error( 'Failed to copy / write to S3 - check your policy?' );
return;
}
WP_CLI::print_value( 'File uploaded to S3 successfully.' );
// Delete the file off S3.
WP_CLI::print_value( 'Attempting to delete file. ' . $s3_path );
$delete = unlink( $s3_path );
// Check that the delete worked.
if ( ! $delete ) {
WP_CLI::error( 'Failed to delete ' . $s3_path );
return;
}
WP_CLI::print_value( 'File deleted from S3 successfully.' );
WP_CLI::success( 'Looks like your configuration is correct.' );
}
private function get_iam_policy() : string {
$bucket = strtok( S3_UPLOADS_BUCKET, '/' );
$path = null;
if ( strpos( S3_UPLOADS_BUCKET, '/' ) !== false ) {
$path = str_replace( strtok( S3_UPLOADS_BUCKET, '/' ) . '/', '', S3_UPLOADS_BUCKET );
}
return '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1392016154000",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:GetBucketAcl",
"s3:GetBucketLocation",
"s3:GetBucketPolicy",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::' . S3_UPLOADS_BUCKET . '/*"
]
},
{
"Sid": "AllowRootAndHomeListingOfBucket",
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::' . $bucket . '"],
"Condition":{"StringLike":{"s3:prefix":["' . ( $path !== null ? $path . '/' : '' ) . '*"]}}
}
]
}';
}
/**
* Create AWS IAM Policy that S3 Uploads requires
*
* It's typically not a good idea to use access keys that have full access to your S3 account,
* as if the keys are compromised through the WordPress site somehow, you don't
* want to give full control via those keys.
*
* @subcommand generate-iam-policy
*/
public function generate_iam_policy() : void {
WP_Cli::print_value( $this->get_iam_policy() );
}
/**
* List files in the S3 bucket
*
* @synopsis [<path>]
*
* @param array{0: string} $args
*/
public function ls( array $args ) : void {
$s3 = Plugin::get_instance()->s3();
$prefix = '';
if ( strpos( S3_UPLOADS_BUCKET, '/' ) !== false ) {
$prefix = trailingslashit( str_replace( strtok( S3_UPLOADS_BUCKET, '/' ) . '/', '', S3_UPLOADS_BUCKET ) );
}
if ( isset( $args[0] ) ) {
$prefix .= trailingslashit( ltrim( $args[0], '/' ) );
}
try {
$objects = $s3->getIterator(
'ListObjectsV2', [
'Bucket' => strtok( S3_UPLOADS_BUCKET, '/' ),
'Prefix' => $prefix,
]
);
/** @var array{Key: string} $object */
foreach ( $objects as $object ) {
WP_CLI::line( str_replace( $prefix, '', $object['Key'] ) );
}
} catch ( Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Copy files to / from the uploads directory. Use s3://bucket/location for S3
*
* @synopsis <from> <to>
*
* @param array{0: string, 1: string} $args
*/
public function cp( array $args ) : void {
$from = $args[0];
$to = $args[1];
if ( is_dir( $from ) ) {
$this->recurse_copy( $from, $to );
} else {
copy( $from, $to );
}
WP_CLI::success( sprintf( 'Completed copy from %s to %s', $from, $to ) );
}
/**
* Upload a directory to S3
*
* @subcommand upload-directory
* @synopsis <from> [<to>] [--concurrency=<concurrency>] [--verbose]
*
* @param array{0: string, 1: string} $args
* @param array{concurrency?: int, verbose?: bool} $args_assoc
*/
public function upload_directory( array $args, array $args_assoc ) : void {
$from = $args[0];
$to = '';
if ( isset( $args[1] ) ) {
$to = $args[1];
}
$s3 = Plugin::get_instance()->s3();
$args_assoc = wp_parse_args(
$args_assoc, [
'concurrency' => 5,
'verbose' => false,
]
);
$transfer_args = [
'concurrency' => $args_assoc['concurrency'],
'debug' => (bool) $args_assoc['verbose'],
'before' => function ( Command $command ) : void {
if ( in_array( $command->getName(), [ 'PutObject', 'CreateMultipartUpload' ], true ) ) {
$acl = defined( 'S3_UPLOADS_OBJECT_ACL' ) ? S3_UPLOADS_OBJECT_ACL : 'public-read';
$command['ACL'] = $acl;
}
},
];
try {
$manager = new Transfer( $s3, $from, 's3://' . S3_UPLOADS_BUCKET . '/' . $to, $transfer_args );
$manager->transfer();
} catch ( Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Delete files from S3
*
* @synopsis <path> [--regex=<regex>]
*
* @param array{0: string} $args
* @param array{regex?: string} $args_assoc
*/
public function rm( array $args, array $args_assoc ) : void {
$s3 = Plugin::get_instance()->s3();
$prefix = '';
$regex = isset( $args_assoc['regex'] ) ? $args_assoc['regex'] : '';
if ( strpos( S3_UPLOADS_BUCKET, '/' ) !== false ) {
$prefix = trailingslashit( str_replace( strtok( S3_UPLOADS_BUCKET, '/' ) . '/', '', S3_UPLOADS_BUCKET ) );
}
if ( isset( $args[0] ) ) {
$prefix .= ltrim( $args[0], '/' );
if ( strpos( $args[0], '.' ) === false ) {
$prefix = trailingslashit( $prefix );
}
}
try {
$s3->deleteMatchingObjects(
strtok( S3_UPLOADS_BUCKET, '/' ),
$prefix,
$regex,
[
'before_delete',
function() {
WP_CLI::line( 'Deleting file' );
},
]
);
} catch ( Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
WP_CLI::success( sprintf( 'Successfully deleted %s', $prefix ) );
}
/**
* Enable the auto-rewriting of media links to S3
*/
public function enable() : void {
update_option( 's3_uploads_enabled', 'enabled' );
WP_CLI::success( 'Media URL rewriting enabled.' );
}
/**
* Disable the auto-rewriting of media links to S3
*/
public function disable() : void {
delete_option( 's3_uploads_enabled' );
WP_CLI::success( 'Media URL rewriting disabled.' );
}
/**
* List all files for a given attachment.
*
* Useful for debugging.
*
* @subcommand get-attachment-files
* @synopsis <attachment-id>
*
* @param array{0: int} $args
*/
public function get_attachment_files( array $args ) : void {
WP_CLI::print_value( Plugin::get_attachment_files( $args[0] ) );
}
/**
* Update the ACL of all files for an attachment.
*
* Useful for debugging.
*
* @subcommand set-attachment-acl
* @synopsis <attachment-id> <acl>
*
* @param array{0: int, 1: 'public-read'|'private'} $args
*/
public function set_attachment_acl( array $args ) : void {
$result = Plugin::get_instance()->set_attachment_files_acl( $args[0], $args[1] );
WP_CLI::print_value( $result );
}
private function recurse_copy( string $src, string $dst ) : void {
$dir = opendir( $src );
@mkdir( $dst );
while ( false !== ( $file = readdir( $dir ) ) ) {
if ( ( '.' !== $file ) && ( '..' !== $file ) ) {
if ( is_dir( $src . '/' . $file ) ) {
$this->recurse_copy( $src . '/' . $file, $dst . '/' . $file );
} else {
WP_CLI::line( sprintf( 'Copying from %s to %s', $src . '/' . $file, $dst . '/' . $file ) );
copy( $src . '/' . $file, $dst . '/' . $file );
}
}
}
closedir( $dir );
}
/**
* Verify that the required constants for the S3 connections are set.
*
* @return bool true if all constants are set, else false.
*/
private function verify_s3_access_constants() {
$required_constants = [
'S3_UPLOADS_BUCKET',
];
// Credentials do not need to be set when using AWS Instance Profiles.
if ( ! defined( 'S3_UPLOADS_USE_INSTANCE_PROFILE' ) || ! S3_UPLOADS_USE_INSTANCE_PROFILE ) {
array_push( $required_constants, 'S3_UPLOADS_KEY', 'S3_UPLOADS_SECRET' );
}
$all_set = true;
foreach ( $required_constants as $constant ) {
if ( ! defined( $constant ) ) {
WP_CLI::error( sprintf( 'The required constant %s is not defined.', $constant ), false );
$all_set = false;
}
}
return $all_set;
}
}