Create a gist now

Instantly share code, notes, and snippets.

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 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
));
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.

This is amazing and it worked perfectly, thank you!

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

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 commented Nov 30, 2016

remove query not working ? any idea why ?

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,

Hi, I am getting 500 error on running this file. I am using easy engine latest version on ubuntu. Can somebody help ?

atlasnetwork commented Feb 6, 2017 edited

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/', '');

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

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.

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

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

Great! It's working perfectly.

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 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 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. 👍

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