I'm attempting to backup lots of website using this php code. The script basically goes through the whole public_html directory and adds all the folders and files recursively and zips them.

Here's what I've got so far:

if (!file_exists('/home/sites/'.$_SERVER['SERVER_NAME'].'/cbitsbackup/')) {
mkdir('/home/sites/'.$_SERVER['SERVER_NAME'].'/cbitsbackup/', 0777, true);
$filefront = '/home/sites/'.$_SERVER['SERVER_NAME'].'/cbitsbackup/backup-'.$_SERVER['SERVER_NAME'].'-day1';
$fileend = '.zip';
$time = time();

$file = $filefront.'-'.$time.$fileend;}
else{$file = $filefront.$fileend;};

function zip_directory($source,$tempfile){
if(!extension_loaded('zip') || !file_exists($source)) return false;
$zip = new ZipArchive();
if(!$zip->open($tempfile,ZIPARCHIVE::CREATE)) return false;
$source = str_replace('\\','/',realpath($source));
if(is_dir($source) === true){
    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
    foreach($files as $file){
        $file = str_replace('\\', '/', realpath($file));
        if(is_dir($file) === true) $zip->addEmptyDir(str_replace($source . '/','', $file . '/'));
        else if(is_file($file) === true) $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));}}
elseif(is_file($source) === true) $zip->addFromString(basename($source), file_get_contents($source));
return $zip->close();}

The main problem at the moment is memory constraints (64M) because I'm running on a shared hosting platform. As far as I can see, the zip file is stored in memory until it is 'completed'. This is problem because I have a lot of websites which are much over this size. Is there anyway to write the zip file progressively to disk so my script isn't killed by the system? Could I even write this in Perl to get around this limit?

  • \$\begingroup\$ Welcome to Code Review! This is one of the gray areas of code review. Given enough memory, your script works, but not given enough memory, it breaks. I personally find your question on the good side of this line. While it may be possible that rewriting it in another language can solve it, the primary focus of Code Review is making the code you put here better. \$\endgroup\$ – Simon Forsberg Nov 1 '14 at 13:05
  • \$\begingroup\$ @simon-andre-forsberg Okay thank you. I was very unsure whether to put my question here or whether it would be better suited on StackOverflow. Do you think I might have some more answers on there? \$\endgroup\$ – harry Nov 1 '14 at 13:22
  • \$\begingroup\$ I would not recommend cross posting. Only ask on StackOverflow if your question gets closed here, currently it does not look like it will get closed here. (no close votes) \$\endgroup\$ – Simon Forsberg Nov 1 '14 at 13:42
  • \$\begingroup\$ Why do you need to backup the files? Isn't this what a revision control system is for? \$\endgroup\$ – Mike Brant Nov 6 '14 at 15:59
  • \$\begingroup\$ @MikeBrant This is pretty much an impossible task without SSH access. Something like rsync would have been nice to use, but to get access to SSH with Heart Internet requires a handwritten form per website. Being a reseller (with 98 sites) this would be very impractical. \$\endgroup\$ – harry Nov 6 '14 at 16:05

As you are using Linux, use this in a PHP file:

<?php system('zip -r backup *'); ?>

This will create a ZIP of all files/directories exists in the directory.

  • 2
    \$\begingroup\$ Thats an idea... Do you think I'm allowed to use system executables on shared hosting? \$\endgroup\$ – harry Nov 1 '14 at 11:20
  • \$\begingroup\$ It depends hosting to hosting. But this can be an easy solution, if you have access to. Give it a try at-least. \$\endgroup\$ – Apul Gupta Nov 1 '14 at 11:21
  • \$\begingroup\$ I contracted my host and they replied saying that i can not use system() or exec() calls. Trying to do this in my script confirmed it. Oddly, they don't block passthru() calls so this is what I'm know using. Thanks for your answer \$\endgroup\$ – harry Nov 3 '14 at 7:46
  • \$\begingroup\$ Why not <?php `zip -r backup *`;? The backtick operator is way shorter and does exactly the same job. Read more on php.net/manual/en/language.operators.execution.php \$\endgroup\$ – Ismael Miguel Aug 4 '15 at 8:43

Depending on your intent, it might be better to skip PHP altogether and just run archiving programs on the command line (if your shared host allows SSH access), or through a cron job. Here are a few examples using programs commonly found on servers:

# Create a Gzipped TAR archive
tar -czf ~/backup.tar.gz /directory/to/archive

# Create a zip archive (`zip` isn't as common as tar in my experience)
zip -ur backup.zip /directory/to/archive

If you want dated backups of each site, that's still well within the scope of a shell command or script:

# This will iterate over all files and directories in the sites folder, so might
# need adjusting if there are other files in /home/sites/
for dir in /home/sites/*;
    do tar -czvf $dir/cbitsbackup/backup-$(date +%y-%m-%d).tar.gz -C $dir public_html;

I'd consider the implications of archiving a site and downloading via a single HTTP request as it looks like you're trying to do: is this exposed/publicly accessible? If it isn't locked down, what is the impact of someone viewing any code in a site or sending many requests to the script (ie. denial of service)?

  • \$\begingroup\$ My host is heart internet that don't allow ssh access without sending a handwritten form with proof of ID. This has to be done on a site by site basis and with over 90 websites (reselling) this would be impractical \$\endgroup\$ – harry Nov 3 '14 at 7:39
  • \$\begingroup\$ The script is also secured on an IP whitelist with htaccess \$\endgroup\$ – harry Nov 3 '14 at 7:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.