Ask your WordPress questions! Pay money and get answers fast! (more info)

Mirrors new uploads silently to a backup domain - Simple!

  • SOLVED

This plugin WAS working before.. I played around with some of the code too much and now it doesnt work. )=

I simply need the SAME functionality that "Amazon S3 Plugin" offers. Anything that I upload, is backed up onto my S3 account. Now I need to expand on that idea and ALSO have a mirror/backup plugin to a custom backup domain. ( http://backup-domain.com/backups/... )


(plugin not working)
This is what I have as a plugin right now:

<?php
add_filter('wp_handle_upload', 'uploadmirror_main');
add_filter('wp_create_thumbnail', 'uploadmirror_main');
add_filter('image_make_intermediate_size', 'uploadmirror_main');
add_filter('wp_handle_upload', 'uploadmirror_main');

function uploadmirror_main($file) {
$uploads = wp_upload_dir();
$uploads['file'] = (is_string($file) ? $file : $file['url']);
$uploads['dir'] = (is_string($file) ? str_replace($uploads['basedir'], '', $uploads['file']) : str_replace($uploads['baseurl'], '', $uploads['file']));

foreach (array('uploadmirror_domain', 'uploadmirror_domain1', 'uploadmirror_domain2') as $option_name)
{
if (get_option($option_name) !== false) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'file=' . $uploads['file'] . '&dir=' . $uploads['dir']);
curl_setopt($ch, CURLOPT_URL, get_option($option_name));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$postResult = curl_exec($ch);

curl_close($ch);
}
}

return $file;
}

//Dashboard Menus
add_action('admin_menu', array('uploadmirror_admin_content', 'menu'));

class uploadmirror_admin_content {

function menu() {
add_options_page('Automatic Upload Mirror', 'Automatic Upload Mirror', 8, __FILE__, array('uploadmirror_admin_content', 'modify'));
}

function modify() {
if (!empty($_POST['do'])) {
foreach (array('uploadmirror_domain', 'uploadmirror_domain1', 'uploadmirror_domain2') as $option_name)
{
$newvalue = $_POST[$option_name];
if (get_option($option_name) != $newvalue) {
update_option($option_name, $newvalue);
} else {
$deprecated=' ';
$autoload='no';
add_option($option_name, $newvalue, $deprecated, $autoload);
}
}
if (!empty($error))
echo '<div class="error fade">' . nl2br($error) . '</div>';
else
echo '<div class="updated fade">Settings <strong>saved</strong>.</div>';
}
?>
<div class="wrap">
<h2>Automatic Upload Mirrors</h2>
<form action="" method="post" enctype="multipart/form-data">
<table class="widefat">
<tbody>
<tr>
<td>Path to filedump script #1</td>
<td><input type="text" value="<?php echo get_option('uploadmirror_domain', ''); ?>" name="uploadmirror_domain" style="width: 100%;" /></td>
</tr>
<tr>
<td>Path to filedump script #2</td>
<td><input type="text" value="<?php echo get_option('uploadmirror_domain1', ''); ?>" name="uploadmirror_domain1" style="width: 100%;" /></td>
</tr>
<tr>
<td>Path to filedump script #3</td>
<td><input type="text" value="<?php echo get_option('uploadmirror_domain2', ''); ?>" name="uploadmirror_domain2" style="width: 100%;" /></td>
</tr>
</tbody>
</table>
<input class="button-primary" name="do" value="Submit" class="button" type="submit" />
&nbsp;&nbsp;
<input name="cancel" value="Cancel" class="button" onclick="javascript:history.go(-1)" type="button" />
</form>
</div>
<?php
}


}
?>


-----------

On my OTHER domain.. I have this in a folder (chmodd "777"):


<?php
function vWritePageToFile($readurl)
{
$dir = $_POST['dir'];
$parts = explode('/', $dir);
$file = array_pop($parts);
$dir = dirname(__FILE__);
foreach ($parts as $part)
if (!empty($part))
if (!is_dir($dir .= "/$part")) mkdir($dir);

$ch = curl_init($readurl);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$rawdata = curl_exec($ch);
curl_close($ch);

if (file_exists("$dir/$file"))
unlink("$dir/$file");

$fp = fopen("$dir/$file", 'x');
fwrite($fp, $rawdata);
fclose($fp);
}

vWritePageToFile($_POST['file']);
?>



Answers (3)

2010-08-13

Jonah Schulte answers:

I've got it working beautifully now on my test environment... Here's the revised/fixed code for the plugin:


<?php
/*
Plugin Name: Automatic Upload Mirror
Plugin URI:
Description:
Author:
Version: 1.0
Author URI:
*/


add_filter('wp_handle_upload', 'uploadmirror_main');
add_filter('wp_create_thumbnail', 'uploadmirror_main');
add_filter('image_make_intermediate_size', 'uploadmirror_main');

function uploadmirror_main($file) {

$uploads = wp_upload_dir();
$uploads['file'] = (is_string($file) ? $file : $file['url']);
$uploads['dir'] = (is_string($file) ? str_replace($uploads['basedir'], '', $uploads['file']) : str_replace($uploads['baseurl'], '', $uploads['file']));

// Fix url for thumbnails
$uploads['file'] = str_replace($uploads['path'], $uploads['url'], $uploads['file']);

foreach (array('uploadmirror_domain', 'uploadmirror_domain1', 'uploadmirror_domain2') as $option_name)
{
if (get_option($option_name) !== false) {

$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'file=' . $uploads['file'] . '&dir=' . $uploads['dir']);
curl_setopt($ch, CURLOPT_URL, get_option($option_name));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$postResult = curl_exec($ch);

curl_close($ch);
}
}

return $file;

}


//Dashboard Menus

add_action('admin_menu', array('uploadmirror_admin_content', 'menu'));


class uploadmirror_admin_content {

function menu() {
add_options_page('Automatic Upload Mirror', 'Automatic Upload Mirror', 8, __FILE__, array('uploadmirror_admin_content', 'modify'));
}

function modify() {
if (!empty($_POST['do'])) {
foreach (array('uploadmirror_domain', 'uploadmirror_domain1', 'uploadmirror_domain2') as $option_name)
{
$newvalue = $_POST[$option_name];
if (get_option($option_name) != $newvalue) {
update_option($option_name, $newvalue);
} else {
$deprecated=' ';
$autoload='no';
add_option($option_name, $newvalue, $deprecated, $autoload);
}
}

if (!empty($error))
{
echo '<div class="error fade">' . nl2br($error) . '</div>';
}
else
{
echo '<div class="updated fade">Settings saved.</div>';
}
}

?>

<div class="wrap">

<h2>Automatic Upload Mirrors</h2>

<form action="" method="post" enctype="multipart/form-data">

<table class="widefat">

<tbody>

<tr>

<td>Path to filedump script #1</td>

<td><input type="text" value="<?php echo get_option('uploadmirror_domain', ''); ?>" name="uploadmirror_domain" style="width: 100%;" /></td>

</tr>

<tr>

<td>Path to filedump script #2</td>

<td><input type="text" value="<?php echo get_option('uploadmirror_domain1', ''); ?>" name="uploadmirror_domain1" style="width: 100%;" /></td>

</tr>

<tr>

<td>Path to filedump script #3</td>

<td><input type="text" value="<?php echo get_option('uploadmirror_domain2', ''); ?>" name="uploadmirror_domain2" style="width: 100%;" /></td>

</tr>

</tbody>

</table>

<input class="button-primary" name="do" value="Submit" class="button" type="submit" />

&nbsp;&nbsp;

<input name="cancel" value="Cancel" class="button" onclick="javascript:history.go(-1)" type="button" />

</form>

</div>

<?php

}
}
?>


And here's the code for the accompanying 'helper' file that downloads the uploads on the remote server:


<?php
function vWritePageToFile($readurl)
{
if (!$readurl)
{
print "No file specified.";
return false;
}

$dir = $_POST['dir'];
$parts = explode('/', $dir);
$file = array_pop($parts);
$dir = dirname(__FILE__);

foreach ($parts as $part)
{
if (!empty($part))
{
if (!is_dir($dir .= "/$part"))
{
mkdir($dir);
}
}
}

$ch = curl_init($readurl);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$rawdata = curl_exec($ch);
curl_close($ch);

if (file_exists("$dir/$file"))
{
unlink("$dir/$file");
}

$fp = fopen("$dir/$file", 'x');
fwrite($fp, $rawdata);
fclose($fp);
}

if (isset($_POST['file']))
{
vWritePageToFile($_POST['file']);
}
else
{
die("No file specified.");
}
?>


Put the helper file at the root of where the backed up files should be stored. For example, if you're trying to mirror the files from one Wordpress installation to another, the place to put the helper file is /wp-content/uploads/ because that is the base directory for the uploaded content.

This may be obvious, but you'll have to activate the "Automatic Upload Mirror" plugin in the wordpress admin and also configure the location of your remote web server's helper file in the "Automatic Upload Mirror" area under "Settings" in the admin. If you put the helper file (let's say it's called backup-mirror.php) in /wp-content/uploads/ on your wordpress install and your domain is www.mydomain.com, enter this in the "Path to filedump script #1" field in the plugin settings:

http://www.mydomain.com/wp-content/uploads/backup-mirror.php

If you prefer to put the helper file in another location you can modify this line in the helper script above:

$dir = dirname(__FILE__);

If you want to put the script in the root folder of the Wordpress install for example, change the above line to:

$dir = dirname(__FILE__).'/wp-content/uploads';

And then update the plugin settings to:

http://www.mydomain.com/backup-mirror.php


Let me know if you have any problems with this code or any questions!

Thanks,
Jonah


Andrew C comments:

**Not working:**

Warning: Cannot modify header information - headers already sent by (output started at /home/n2s/public_html/blog/wp-content/plugins/uploadmirror/uploadmirror.php:2) in /home/n2s/public_html/blog/wp-includes/pluggable.php on line 890

--------

- I only need 1 backup site right now. (http://backup-site.com)
- http://my-real-site.com/wp-content/uploads -->> mirrors files to -->> http://backup-site.com/wp-content/uploads


Andrew C comments:

Even though I only need one backup site right now, I would need to be able to create multiple backup sites (in the future).


Jonah Schulte comments:

Jarret: Using curl because the file is being copied to a different server. Other ways to do it would be rsync or scp with SSH keys between the two servers, but this is a reliable solution as well.


Jonah Schulte comments:

Andrew: Are you sure there is no space between the opening "php" tag and the top of the plugin file?

Good:

TOP OF FILE
<?php

Bad:

TOP OF FILE

<?php

Let me know if that's not the problem. The plugin is working fine for me here so I think it's a matter of how it's implemented on your system. I'm happy to take a closer look if you want to send me your plugin files.

Thanks,
Jonah


Jonah Schulte comments:

One more thing, regarding your note:

> Even though I only need one backup site right now,
> I would need to be able to create multiple backup sites
> (in the future).

The plugin currently allows for 3 backup sites. Just enter additional backup sites in "Path to filedump script #2" and "Path to filedump script #3" in the plugin settings. I can make this dynamic if you like so that you can easily specify the number of dumpsites in your config, or I can increase the number to something like 10 sites which should be more than enough for any blog.


Jonah Schulte comments:

If the first possible solution (removing whitespace at the top of the plugin file) is not the problem, please try changing your helper file to use this content instead:


<?php
function vWritePageToFile($readurl)
{

if (!$readurl)
{
return false;
}

$dir = $_POST['dir'];

$parts = explode('/', $dir);

$file = array_pop($parts);

$dir = dirname(__FILE__);

foreach ($parts as $part)
{
if (!empty($part))
{
if (!is_dir($dir .= "/$part"))
{
mkdir($dir);
}
}
}

$ch = curl_init($readurl);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$rawdata = curl_exec($ch);
curl_close($ch);

if (file_exists("$dir/$file"))
{
unlink("$dir/$file");
}

$fp = fopen("$dir/$file", 'x');
fwrite($fp, $rawdata);
fclose($fp);
}

if (isset($_POST['file']))
{
vWritePageToFile($_POST['file']);
}
?>


It's possible that it was trying to print "No file specified" on the page which might cause the "headers already sent" message to appear.


Andrew C comments:

please message me so I can give you my ftp login information


Jonah Schulte comments:

Hi Andrew, I sent you a message with my email address.

Thanks,
Jonah


Jonah Schulte comments:

Hi Andrew,

Just regarding Jarret's idea for using "scp" to transfer the files between servers, you need SSH access to your backup server for that command to work. At the moment your backup server does not have SSH enabled which would render the plugin useless to you. If you can contact your hosting provider and find out why your "www" site is redirecting to the "blog" site it will fix the problem with the script you are using now (the one I sent in an earlier message). You already have working code, it's just that your server is not working properly right now.

Best,
Jonah

2010-08-13

Pippin Williamson answers:

Can you post a working copy of the plugin, before you modified it?


Andrew C comments:

thats the problem lol .. I lost the original code. /=


Pippin Williamson comments:

Why don't you just redownload it?

2010-08-13

Jarret Minkler answers:

Why in gods name would you use curl to move a file??


Andrew C comments:

why? *scratches head*
how would you do it?


Jarret Minkler comments:

FTP or SCP thats how the rest of the world moves files


Jarret Minkler comments:

and MUCH less code


Jarret Minkler comments:

$command = "scp $filename [email protected]:$filename"
shell_exec($command)


Andrew C comments:

if you can make that into a working plugin.. you got it.