Instantly share code, notes, and snippets.

Embed
What would you like to do?
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
/* ======================================================
This script is NOT FULLY TESTED (not tested on Windows Server either)
USE AT YOUR OWN RISK - development environment Ubuntu Linux 14.04.3 LTS
The purpose of this script is for small websites and blogs
to have their existing media to work through Amazon S3
There's a great plugin, WP Offload S3, that we'll be tapping
into...it works great for new media, but this is a quick
fix for EXISTING media - media added before you start
using WP Offload S3.
This script is not fully tested, but should be useful for
most situations. It does create a backup of your database,
though it's not tested to work 100% in all hosting scenarios.
Put this file in your WordPress root directory, where wp-config.php is.
You must also already have these 2 plugins installed and configured:
- https://wordpress.org/plugins/amazon-web-services/
- https://wordpress.org/plugins/amazon-s3-and-cloudfront/
TURN OFF CACHING if you have it on your site. Re-enable it after
everything is done.
======================================================
STEPS
1) Manually upload all of your existing /wp-content/uploads/ files to the
Amazon S3 bucket (the bucket you configured WP Offload S3 to use for new images)
2) Add and configure plugins (the 2 listed above)
3) Run this script from the root directory of your WordPress site
======================================================
Developer: TJ Nevis
Website: http://blog.TJNevis.com, http://NevisTechnology.com
More Info: http://blog.tjnevis.com/wordpress-and-amazon-s3-quick-fix-for-existing-media-to-be-served-on-amazon-s3/
Last Updated: 04/19/2016
====================================================== */
require_once 'wp-config.php';
require_once 'wp-content/plugins/amazon-s3-and-cloudfront/wordpress-s3.php';
global $table_prefix;
echo '<h1>Move Existing Media to Amazon S3</h1>';
echo '<h3>By TJ Nevis [<a href="http://NevisTechnology.com?ref=S3Script" target="_blank">NevisTechnology.com</a>] Detailed blog post <a href="http://blog.tjnevis.com/wp-offload-s3-quick-fix-for-existing-media/" target="_blank">here</a></h3>';
/* ======================================================
First step, we're going to back up the database and
save it in the the root directory of your site (where this file is)
====================================================== */
$dbHost = $wpdb->dbhost;
$dbName = $wpdb->dbname;
$dbPassword = $wpdb->dbpassword;
$dbSaveFileLocation = dirname(__FILE__) . '/backup-' . date('Y-m-d-h:i:s', time()) . '.sql';
$dbUser = $wpdb->dbuser;
exec("mysqldump --user=$dbUser --password=$dbPassword --host=$dbHost $dbName > $dbSaveFileLocation");
/* ======================================================
Let's get set up with by grabbing WP Offload S3 values
====================================================== */
amazon_web_services_require_files(); // Thanks k0nG
$aws = new Amazon_Web_Services( __FILE__ ); // Thanks k0nG
$awsS3 = new Amazon_S3_And_CloudFront(__FILE__, $aws); // Thanks k0nG
$bucket = ( !empty( $awsS3->get_setting('cloudfront') ) ) ? $awsS3->get_setting('cloudfront') : $awsS3->get_setting('bucket'); // If you're using a CDN and the setting is saved, use that for CloudFront URL replcaement, otherwise use the S3 bucket name
$region = $awsS3->get_setting('region'); // Thanks k0nG
$folderPrefix = $awsS3->get_setting('object-prefix');
/* ======================================================
Check if the user is requesting to remove the existing media updates
====================================================== */
if( isset($_GET['remove']) && $_GET['remove'] ) { // ?removeS3Update=true
if( $dbConnection = mysqli_connect($dbHost, $dbUser, $dbPassword, $dbName) ) {
$removeAmazonS3Info = "DELETE FROM " . $table_prefix . "postmeta WHERE meta_key = 'amazonS3_info';";
$reversePostContentHref = updatePostContent(
'href',
$table_prefix . 'posts',
get_site_url( $wpdb->blogid ) . '/' . $folderPrefix,
"https://$bucket.s3.amazonaws.com/$folderPrefix",
true
);
$reversePostContentSrc = updatePostContent(
'src',
$table_prefix . 'posts',
get_site_url( $wpdb->blogid ) . '/' . $folderPrefix,
"https://$bucket.s3.amazonaws.com/$folderPrefix",
true
);
echo 'RUNNING COMMAND: ' . $removeAmazonS3Info . ' - ';
if( $dbConnection->query($removeAmazonS3Info) ) {
echo ' <strong>TRUE, ' . $dbConnection->affected_rows . ' rows affected</strong><br />';
}
echo 'RUNNING COMMAND: ' . $reversePostContentHref . ' - ';
if( $dbConnection->query($reversePostContentHref) ) {
echo ' <strong>TRUE, ' . $dbConnection->affected_rows . ' rows affected</strong><br />';
}
echo 'RUNNING COMMAND: ' . $reversePostContentSrc . ' - ';
if( $dbConnection->query($reversePostContentSrc) ) {
echo ' <strong>TRUE, ' . $dbConnection->affected_rows . ' rows affected</strong><br />';
}
}
echo '<h3>DONE with removing records for WP Offload S3 - reverted back to serving from the local server</h3>';
exit(); // Don't do the rest of the script
}
/* ======================================================
Start fresh, delete data thatis from WP Offload S3
====================================================== */
$wpdb->delete($table_prefix . 'postmeta',
array(
'meta_key' => 'amazonS3_info'
)
);
/* ======================================================
Grab the attachments from the database, we'll need
the meta_value (image name), and the post ID it's related to
====================================================== */
$picturesToUpdate = $wpdb->get_results("SELECT * FROM " . $table_prefix . "postmeta WHERE meta_key = '_wp_attached_file'");
foreach($picturesToUpdate as $picture) {
$pictureMetaData = serialize(array(
'bucket' => $bucket,
'key' => $folderPrefix . $picture->meta_value,
'region' => $region // Thanks k0nG
));
/* ======================================================
Now let's insert the record that WP Offload S3 looks for
to change the image URL to your S3 URL
====================================================== */
$wpdb->insert($table_prefix . 'postmeta',
array(
'post_id' => $picture->post_id,
'meta_key' => 'amazonS3_info',
'meta_value' => $pictureMetaData
)
);
}
if( $dbConnection = mysqli_connect($dbHost, $dbUser, $dbPassword, $dbName) ) {
$hrefMySQLUpdate = updatePostContent(
'href',
$table_prefix . 'posts',
get_site_url( $wpdb->blogid ) . '/' . $folderPrefix,
"https://$bucket.s3.amazonaws.com/$folderPrefix"
);
$srcMySQLUpdate = updatePostContent(
'src',
$table_prefix . 'posts',
get_site_url( $wpdb->blogid ) . '/' . $folderPrefix,
"https://$bucket.s3.amazonaws.com/$folderPrefix"
);
echo 'RUNNING COMMAND: ' . $hrefMySQLUpdate . ' - ';
if( $dbConnection->query($hrefMySQLUpdate) ) {
echo ' <strong>TRUE, ' . $dbConnection->affected_rows . ' rows affected</strong><br />';
}
echo 'RUNNING COMMAND: ' . $srcMySQLUpdate . ' - ';
if( $dbConnection->query($srcMySQLUpdate) ) {
echo ' <strong>TRUE, ' . $dbConnection->affected_rows . ' rows affected</strong><br />';
}
}
echo '<h3>DONE with adding records for WP Offload S3 to recognize the image on S3</h3>';
function updatePostContent($type, $table, $blog, $s3bucket, $reverse = FALSE) {
// $reverse is to remove the post_content updates and put them back to serving locally
$from = ( !$reverse ) ? $blog : $s3bucket;
$to = ( !$reverse ) ? $s3bucket : $blog;
return "UPDATE $table SET post_content = replace(post_content, '$type=\"$from', '$type=\"$to');";
}
?>
@k0nG

This comment has been minimized.

Show comment
Hide comment
@k0nG

k0nG Mar 17, 2016

Hi,

Great script. I had a little trouble getting it to work as the Amazon_S3_And_CloudFront now seems to need some arguments in the constructor. If you require wp-content/plugins/amazon-web-services/amazon-web-services.php and then construct Amazon_Web_Services first then you can pass that into Amazon_S3_And_CloudFront like so:

amazon_web_services_require_files();   // Import AWS plugin classes.
$aws = new Amazon_Web_Services( __FILE__ );
$awsS3 = new Amazon_S3_And_CloudFront(__FILE__, $aws);

Also i'm using an EU West bucket, you can also then get the bucket region using:

$region = $awsS3->get_setting('region');

And update the attachment meta data update to:

$pictureMetaData = serialize(array(
    'bucket'    => $bucket,
    'key'       => $folderPrefix . $picture->meta_value,
    'region'    => $region
));

k0nG commented Mar 17, 2016

Hi,

Great script. I had a little trouble getting it to work as the Amazon_S3_And_CloudFront now seems to need some arguments in the constructor. If you require wp-content/plugins/amazon-web-services/amazon-web-services.php and then construct Amazon_Web_Services first then you can pass that into Amazon_S3_And_CloudFront like so:

amazon_web_services_require_files();   // Import AWS plugin classes.
$aws = new Amazon_Web_Services( __FILE__ );
$awsS3 = new Amazon_S3_And_CloudFront(__FILE__, $aws);

Also i'm using an EU West bucket, you can also then get the bucket region using:

$region = $awsS3->get_setting('region');

And update the attachment meta data update to:

$pictureMetaData = serialize(array(
    'bucket'    => $bucket,
    'key'       => $folderPrefix . $picture->meta_value,
    'region'    => $region
));
@TJNevis

This comment has been minimized.

Show comment
Hide comment
@TJNevis

TJNevis Apr 19, 2016

Hey,

Awesome. Thanks for the revision. I made the adjustments and used it on one of my sites. Works perfect.

Thanks again for the update.

I've updated the snippet.

Owner

TJNevis commented Apr 19, 2016

Hey,

Awesome. Thanks for the revision. I made the adjustments and used it on one of my sites. Works perfect.

Thanks again for the update.

I've updated the snippet.

@UseDotCom

This comment has been minimized.

Show comment
Hide comment
@UseDotCom

UseDotCom Sep 22, 2016

This is amazing and it worked perfectly, thank you!

I was dreading figuring this out, you saved me a lot of time.

UseDotCom commented Sep 22, 2016

This is amazing and it worked perfectly, thank you!

I was dreading figuring this out, you saved me a lot of time.

@phumpal

This comment has been minimized.

Show comment
Hide comment
@phumpal

phumpal Nov 4, 2016

Thanks for this @TJNevis.

I tested this on Xenial with PHP 7 and one thing I might add is that MySQL functions have been deprecated as of PHP 5.5.0.

Use of mysqli extensions is recommended.

To update in vim for example

:%s/mysql_/mysqli_/gc

One note:

mysqli expects two parameters otherwise there are warnings. For example continuing to use the procedural style on line 155

$db = mysqli_connect($dbHost, $dbUser, $dbPassword);
if($db) {

then on line 172

mysqli_query($db, $hrefMySQLUpdate)

and line 177

mysqli_query($db, $srcMySQLUpdate)

phumpal commented Nov 4, 2016

Thanks for this @TJNevis.

I tested this on Xenial with PHP 7 and one thing I might add is that MySQL functions have been deprecated as of PHP 5.5.0.

Use of mysqli extensions is recommended.

To update in vim for example

:%s/mysql_/mysqli_/gc

One note:

mysqli expects two parameters otherwise there are warnings. For example continuing to use the procedural style on line 155

$db = mysqli_connect($dbHost, $dbUser, $dbPassword);
if($db) {

then on line 172

mysqli_query($db, $hrefMySQLUpdate)

and line 177

mysqli_query($db, $srcMySQLUpdate)
@duchu

This comment has been minimized.

Show comment
Hide comment
@duchu

duchu Nov 30, 2016

remove query not working ? any idea why ?

duchu commented Nov 30, 2016

remove query not working ? any idea why ?

@sidimar

This comment has been minimized.

Show comment
Hide comment
@sidimar

sidimar Jan 13, 2017

Hi,
Great script, it's working perfect.
I wondering if you had the same issue I am having with PDFs. It's changed the PDFs URL to amazon (perfect) but now I have to change the links to PDFs. I am truing figure out a quick way to do that instead go through one by one.
Regards,

sidimar commented Jan 13, 2017

Hi,
Great script, it's working perfect.
I wondering if you had the same issue I am having with PDFs. It's changed the PDFs URL to amazon (perfect) but now I have to change the links to PDFs. I am truing figure out a quick way to do that instead go through one by one.
Regards,

@atlasnetwork

This comment has been minimized.

Show comment
Hide comment
@atlasnetwork

atlasnetwork Feb 6, 2017

Not sure if its a plugin that is causing this or what, but in some cases /wp-content/uploads is repeated in the replacement so it reads s3bucketurl.com/wp-content/uploads//wp-content/uploads/filename (with the two slashes).

Any idea on how to fix this?

Can I run a search and replace on the database for /wp-content/uploads//wp-content/uploads/ and replace with /wp-content/uploads/ ? What table/column would I run this on?

This seems to happen only when the file is in the wp-content/uploads root directory

** I ended up fixing this with UPDATE wp_postmeta SET meta_value = replace(meta_value, '/wp-content/uploads/', '');

atlasnetwork commented Feb 6, 2017

Not sure if its a plugin that is causing this or what, but in some cases /wp-content/uploads is repeated in the replacement so it reads s3bucketurl.com/wp-content/uploads//wp-content/uploads/filename (with the two slashes).

Any idea on how to fix this?

Can I run a search and replace on the database for /wp-content/uploads//wp-content/uploads/ and replace with /wp-content/uploads/ ? What table/column would I run this on?

This seems to happen only when the file is in the wp-content/uploads root directory

** I ended up fixing this with UPDATE wp_postmeta SET meta_value = replace(meta_value, '/wp-content/uploads/', '');

@leedotpang

This comment has been minimized.

Show comment
Hide comment
@leedotpang

leedotpang Feb 21, 2017

You sir, are a gentleman, and a scholar. Thank you for sharing!

leedotpang commented Feb 21, 2017

You sir, are a gentleman, and a scholar. Thank you for sharing!

@vumhoang

This comment has been minimized.

Show comment
Hide comment
@vumhoang

vumhoang Mar 7, 2017

@TJNevis: Have you tried this with Offload S3 Lite? I am trying to do the same job but the php file doesn't work.

vumhoang commented Mar 7, 2017

@TJNevis: Have you tried this with Offload S3 Lite? I am trying to do the same job but the php file doesn't work.

@Silvercast

This comment has been minimized.

Show comment
Hide comment
@Silvercast

Silvercast Mar 7, 2017

I have the same interest. Let me know if it works with Lite @vumhoang

Silvercast commented Mar 7, 2017

I have the same interest. Let me know if it works with Lite @vumhoang

@vumhoang

This comment has been minimized.

Show comment
Hide comment
@vumhoang

vumhoang Mar 14, 2017

@Silvercast: so far I couldn't make it work. :(

vumhoang commented Mar 14, 2017

@Silvercast: so far I couldn't make it work. :(

@robalves-tpro

This comment has been minimized.

Show comment
Hide comment
@robalves-tpro

robalves-tpro May 9, 2017

Great! It's working perfectly.

robalves-tpro commented May 9, 2017

Great! It's working perfectly.

@dokomade99

This comment has been minimized.

Show comment
Hide comment
@dokomade99

dokomade99 May 12, 2017

I want to ask

How to setting amazon s3 in wordpress so it does not automatically to my cdn? I want to directly use a bucket that like ditutorial. But instead automatically to my cdn croudfront. Please help
I see the tutorial from your blog

dokomade99 commented May 12, 2017

I want to ask

How to setting amazon s3 in wordpress so it does not automatically to my cdn? I want to directly use a bucket that like ditutorial. But instead automatically to my cdn croudfront. Please help
I see the tutorial from your blog

@raydoll

This comment has been minimized.

Show comment
Hide comment
@raydoll

raydoll May 17, 2017

This was a huge help. I was literally just discussing doing this for a client of mine. I had to modify a bit for my situation but miles simpler than starting from scratch. Great work you put into this! Many thanks my man.

raydoll commented May 17, 2017

This was a huge help. I was literally just discussing doing this for a client of mine. I had to modify a bit for my situation but miles simpler than starting from scratch. Great work you put into this! Many thanks my man.

@crankeye

This comment has been minimized.

Show comment
Hide comment
@crankeye

crankeye Jul 6, 2017

Much appreciated. Though the https://$bucket.s3.amazonaws.com/$folderPrefix will not work if you are using cloud front. Should be https://$bucket.cloudfront.net/$folderPrefix. Other that that worked perfect. 👍

crankeye commented Jul 6, 2017

Much appreciated. Though the https://$bucket.s3.amazonaws.com/$folderPrefix will not work if you are using cloud front. Should be https://$bucket.cloudfront.net/$folderPrefix. Other that that worked perfect. 👍

@soter19

This comment has been minimized.

Show comment
Hide comment
@soter19

soter19 Aug 3, 2017

Well done! It was very useful!!!

soter19 commented Aug 3, 2017

Well done! It was very useful!!!

@bluemalkin

This comment has been minimized.

Show comment
Hide comment
@bluemalkin

bluemalkin Aug 7, 2017

Wonderful script which saved my bacon, thank you !

bluemalkin commented Aug 7, 2017

Wonderful script which saved my bacon, thank you !

@diegodurante

This comment has been minimized.

Show comment
Hide comment
@diegodurante

diegodurante Aug 9, 2017

Awesome! It works like a charm!

FYI I had to disable Maintenance Mode to let it works properly ;)

Many many thanks!

diegodurante commented Aug 9, 2017

Awesome! It works like a charm!

FYI I had to disable Maintenance Mode to let it works properly ;)

Many many thanks!

@gregshep

This comment has been minimized.

Show comment
Hide comment
@gregshep

gregshep Sep 12, 2017

Perfect! Worked for me too!
I added this bucket policy to my media bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BUCKETNAMEHERE/*"
        }
    ]
}

Thank you for maintaining this great utility.

gregshep commented Sep 12, 2017

Perfect! Worked for me too!
I added this bucket policy to my media bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BUCKETNAMEHERE/*"
        }
    ]
}

Thank you for maintaining this great utility.

@xgiadmin

This comment has been minimized.

Show comment
Hide comment
@xgiadmin

xgiadmin Jan 24, 2018

Awesome script! Thank you for providing. Any ideas on how we could we modify this to move from one AWS Bucket to another? Say all files exist in a bucket for development then we want to move those to another AWS bucket for production.

xgiadmin commented Jan 24, 2018

Awesome script! Thank you for providing. Any ideas on how we could we modify this to move from one AWS Bucket to another? Say all files exist in a bucket for development then we want to move those to another AWS bucket for production.

@gbot

This comment has been minimized.

Show comment
Hide comment
@gbot

gbot Sep 18, 2018

In case it's useful to others, I have rewritten this script to work correctly with the latest version of WP Offload S3 Lite, which no longer requires the AWS plugin (https://wordpress.org/plugins/amazon-web-services/).

I have also tried to make it easier to use (and look a little prettier).

Please do let me know if you have any suggestions for improvement.

https://gist.github.com/gbot/0c10f03df28315fbe9ad8968ab110285

gbot commented Sep 18, 2018

In case it's useful to others, I have rewritten this script to work correctly with the latest version of WP Offload S3 Lite, which no longer requires the AWS plugin (https://wordpress.org/plugins/amazon-web-services/).

I have also tried to make it easier to use (and look a little prettier).

Please do let me know if you have any suggestions for improvement.

https://gist.github.com/gbot/0c10f03df28315fbe9ad8968ab110285

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment