简体   繁体   English

在本地主机和服务器上使用php创建备份

[英]creating a backup using php on localhost and server

I created my own backup system for backing up my database and various folders that are subject to change on my site (for simplicity assume one folder -> folder_to_backup and the files and folders therein that I want to preserve ). 我创建了自己的备份系统来备份数据库和站点上可能更改的各种文件夹(为简单起见,假设一个文件夹-> folder_to_backup 以及要保留的其中的文件和文件夹 )。 The only issue is, it doesn't work on local environments (localhost) and this is something I would like to address. 唯一的问题是,它在本地环境(本地主机)上不起作用,这是我要解决的问题。 Heres the class that does the actual zipping (forgot where I got it from): 这是进行实际压缩的类(忘了我从哪里得到的):

    function __construct($file, $folders = array(), $ignored = NULL)
    {
        $this->zip = new ZipArchive();
        $this->ignored_names = is_array($ignored) ? $ignored : $ignored ? array(
            $ignored
        ) : array();
        if ($this->zip->open($file, ZIPARCHIVE::CREATE) !== TRUE) {
            return FALSE;
        }
        $folder = substr($folder, -1) == '/' ? substr($folder, 0, strlen($folder) - 1) : $folder;
        if (strstr($folder, '/')) {
            $this->root = substr($folder, 0, strrpos($folder, '/') + 1);
            $folder = substr($folder, strrpos($folder, '/') + 1);
        }
        foreach ($folders as $folder) {
            $this->zip($folder);
        }
        $this->zip->close();
    }
    function zip($folder, $parent = NULL)
    {
        $full_path = $this->root . $parent . $folder;
        $zip_path = $parent . $folder;
        $this->zip->addEmptyDir($zip_path);
        $dir = new DirectoryIterator($full_path);
        foreach ($dir as $file) {
            if (!$file->isDot()) {
                $filename = $file->getFilename();
                if (!in_array($filename, $this->ignored_names)) {
                    if ($file->isDir()) {
                        $this->zip($filename, $zip_path . '/');
                    } else {
                        $this->zip->addFile($full_path . '/' . $filename, $zip_path . '/' . $filename);
                    }
                }
            }
        }
    }

So using the above code I create my zip files, however I have to send the $folder with a realpath() for the iterator to work, and thus on a local environment I get something like this: 因此,使用上面的代码创建了我的zip文件,但是我必须向$folder发送带有realpath()的迭代器才能工作,因此在本地环境中,我会得到以下信息:

C:\\xampp\\htdocs\\sitename\\cms\\files\\folder_to_backup\\

and on a http environment: 并在http环境中:

/opt/www/prezent/sitename/HTML/cms/files/folder_to_backup/

So say I wanted to update the localhost copy of my site I download the file and for obvious reasons I cannot unzip it as the directory structure isn't compatible, nor are the directory separators compatible. 所以说我想更新站点的本地主机副本,我下载了文件,由于明显的原因,我无法解压缩该文件,因为目录结构不兼容,目录分隔符也不兼容。

So I figured I could isolate the commonality being 'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup 所以我想我可以将通用性隔离为'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup 'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup 'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup . 'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup So essentially instead of having all the folders leading up to the folder cms I would just have the structure 因此,从本质上讲,不是让所有文件夹都指向文件夹cms,而是让结构

DIR
   files /
      folder_to_backup /
         some files and folders ... etc

and then on restore instead of extracting it to the /opt/ or C:\\ via realpath(DIRECTORY_SEPARATOR) . 然后还原,而不是通过realpath(DIRECTORY_SEPARATOR)将其提取到/opt/C:\\ I would use something similar to realpath(dirname(__FILE__)) or what have you. 我会使用类似于realpath(dirname(__FILE__))或您拥有的东西。

So to be succinct my question is how can I obtain the above file structure (excluding the realpath up to /files/ , knowing that I have to feed the zip creator a realpath so that it can find the files? 简而言之,我的问题是我如何才能获得上述文件结构(不包括/files/的realpath,知道我必须向zip创建者提供一个realpath以便它可以找到文件?

Use This script: 使用此脚本:

1) Set execution time to 0 if in case your site is huge and will take much time for back-up as default execution time for PHP is 30 seconds. 1)如果您的站点很大并且将花费大量时间进行备份,则将执行时间设置为0,因为PHP的默认执行时间为30秒。

ini_set("max_execution_time", 0);

2) By using below code we are creating a directory in which you're going to stored your zip. 2)通过使用以下代码,我们创建了一个目录,您将在其中存储zip。 In my case my directory name is 'site-backup-stark'. 在我的情况下,我的目录名称是“ site-backup-stark”。

$dir = "site-backup-stark";
if(!(file_exists($dir))) {
mkdir($dir, 0777);
}

3) Set your site credentials. 3)设置您的站点凭据。

$host = "localhost"; //host name
$username = "root"; //username
$password = ""; // your password
$dbname = "wp_test"; // database name

4) We are going to save our backup in zip format so create an object of zip. 4)我们将以zip格式保存备份,因此创建一个zip对象。

$zip = new ZipArchive();

5) Call the function backup_tables. 5)调用函数backup_tables。

backup_tables($host, $username, $password, $dbname);

6) Define the function backup_tables which will create a database sql file. 6)定义函数backup_tables,它将创建数据库sql文件。

/* backup the db OR just a table */
function backup_tables($host,$user,$pass,$name,$tables = '*')
{
$con = mysql_connect($host,$user,$pass);
mysql_select_db($name,$con);

//get all of the tables
if($tables == '*')
{
$tables = array();
$result = mysql_query('SHOW TABLES');
while($row = mysql_fetch_row($result))
{
$tables[] = $row[0];
}
}
else
{
$tables = is_array($tables) ? $tables : explode(',',$tables);
}
$return = "";

//cycle through
foreach($tables as $table)
{
$result = mysql_query('SELECT * FROM '.$table);
$num_fields = mysql_num_fields($result);
$return.= 'DROP TABLE '.$table.';';
$row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table));
$return.= "nn".$row2[1].";nn";

while($row = mysql_fetch_row($result))
{
$return.= 'INSERT INTO '.$table.' VALUES(';
for($j=0; $j<$num_fields; $j++)
{
$row[$j] = addslashes($row[$j]);
$row[$j] = preg_replace("#n#","n",$row[$j]);
if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
if ($j<($num_fields-1)) { $return.= ','; }
}
$return.= ");n";
}
$return.="nnn";
}

//save file
$handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
fwrite($handle,$return);
fclose($handle);
}

7) Convert .sql file in .sql.zip file and remove the .sql file. 7)将.sql文件转换为.sql.zip文件,然后删除.sql文件。

if (glob("*.sql") != false)
{
$filecount = count(glob("*.sql"));
$arr_file = glob("*.sql");

for($j=0;$j<$filecount;$j++)
{
$res = $zip->open($arr_file[$j].".zip", ZipArchive::CREATE);
if ($res === TRUE)
{
$zip->addFile($arr_file[$j]);
$zip->close();
unlink($arr_file[$j]);
}
}
}

8) Now we have to get current folder name in which our php file is present. 8)现在,我们必须获取其中存在我们的php文件的当前文件夹名称。 This is because when we have to move all folders and files from root directory to our zip. 这是因为当我们必须将所有文件夹和文件从根目录移动到zip时。

//get the current folder name-start
$path = dirname($_SERVER['PHP_SELF']);
$position = strrpos($path,'/') + 1;
$folder_name = substr($path,$position);
//get the current folder name-end

9) Create a name for zip file. 9)为zip文件创建一个名称。 I have created it based on today's date so that we can easily find date of last backup. 我已经根据今天的日期创建了它,以便我们可以轻松找到上次备份的日期。 Also I have append 'stark-' to a name of zip file which we use in next procedures. 另外,我在后面的过程中使用的zip文件名称后附加了“ stark-”。

$zipname = date('Y/m/d');
$str = "stark-".$zipname.".zip";
$str = str_replace("/", "-", $str);

10) Add all files from current folder in newly created zip file. 10)将当前文件夹中的所有文件添加到新创建的zip文件中。

// open archive
if ($zip->open($str, ZIPARCHIVE::CREATE) !== TRUE) {
die ("Could not open archive");
}
// initialize an iterator
// pass it the directory to be processed
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("../$folder_name    /"));
// iterate over the directory
// add each file found to the archive

foreach ($iterator as $key=>$value) {
if( strstr(realpath($key), "stark") == FALSE) {
$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}

}
// close and save archive
$zip->close();
echo "Archive created successfully.";

11) Remove all our .sql.zip files from root directory as we moved it in another folder. 11)当我们将它移到另一个文件夹中时,从根目录中删除所有.sql.zip文件。

if(glob("*.sql.zip") != false) {
$filecount = count(glob("*.sql.zip"));
$arr_file = glob("*.sql.zip");

for($j=0;$j<$filecount;$j++)
{
unlink($arr_file[$j]);
}
}

12) Now move a copy of our zip file to a direcotry which we have created in step 2. 12)现在,将我们的zip文件的副本移至在步骤2中创建的目录。

//get the array of zip files
if(glob("*.zip") != false) {
$arr_zip = glob("*.zip");
}

//copy the backup zip file to site-backup-stark folder
foreach ($arr_zip as $key => $value) {
if (strstr($value, "stark")) {
$delete_zip[] = $value;
copy("$value", "$dir/$value");
}
}

13) Delete a zip file from root directory as we moved it in another directory. 13)当我们将其移动到另一个目录时,请从根目录中删除一个zip文件。

for ($i=0; $i < count($delete_zip); $i++) {
unlink($delete_zip[$i]);
}

So because I couldn't find a direct answer, and was getting nowhere, I did alot of research on this site and by looking up other backup methodologies and I've come to create a class that combines many answers on stack related to this into one class. 因此,由于我找不到直接的答案,而且一无所获,因此我在该站点上进行了很多研究,并通过查找其他备份方法进行了研究,因此我开始创建一个类,该类将与此有关的堆栈上的许多答案组合到了一起一堂课 I've even added a way to ignore files and folders, and a sort of automated way to find out what directory the actual zip architecture should start in. I have confirmed that it works on windows (via xampp) and my site server. 我什至还添加了一种忽略文件和文件夹的方法,以及一种自动查找实际zip体系结构应从哪个目录开始的自动化方法。我已经确认它可以在Windows(通过xampp)和我的站点服务器上运行。 Hopefully this saves someone some headache! 希望这可以节省一些人的头痛!

Usage outlined at the end of the class! 在课程结束时概述用法! If anyone wants to refactor it, feel free, but test it and then update my answer! 如果有人想重构它,请放心,但是要对其进行测试,然后更新我的答案!

<?php
class ZipFolder
{
    /** NON CONFIGURABLE **/
    protected $zip;
    protected $SQLinit = false;
    /** CONFIGURABLE **/
    protected $overwrite = true;                    // overwrite file if exists (just incase unlink doesnt work)
    protected $nback = 1;                           /* if you have a folder such as /HTML/ in your doc root and
                                                       your website index.html begings in the /HTML/ dir this
                                                       number should be one. add +1 for every directory until your
                                                       website frontend homepage */
    protected $sqlDirInZip = 'sql';                 // sql dir inside
    protected $ignored_files = array('.DS_STORE');  // specific files to ignore (Note: also works with extensions)
    protected $ignored_folders = array('_notes');   // folders to ignore

    function __construct($destination, $sources = array(), $SQLfile = NULL)
    {
        if (!extension_loaded('zip')) {
            return false;
        }
        $this->zip = new ZipArchive();
        if (file_exists($destination)) {
            @unlink($destination);
        }
        // ZIPARCHIVE::OVERWRITE ??
        if ($this->zip->open($destination, $this->overwrite == true ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== TRUE) {
            return false;
        }
        if (isset($SQLfile)) {
            // zip sql file in sql directory
            $this->SQLinit = true;
            $SQLfile = str_replace('\\', DIRECTORY_SEPARATOR, realpath($SQLfile));
            $this->zip->addEmptyDir($this->sqlDirInZip);
            $this->zip->addFromString($this->sqlDirInZip . DIRECTORY_SEPARATOR . basename($SQLfile), file_get_contents($SQLfile));
        }
        foreach ($sources as $source) {
            $this->zippy($source, true);
        }
        if ($this->SQLinit) {
            if (!$this->verifySQL($destination)) {
                // couldn't verify that sql made it we close dir and remove it, return a false
                $this->zip->close();
                unlink($destination);
                return false;
            }
        }
        $this->zip->close();
        return true;
    }
    /**
     *
     * Count Slashes
     *
     * Given a $str will return the amount of slashes in the string
     * We can use this to find the diff (new func needed) between 
     *  /HTML/ and where we are now, and then send that number to minus
     *
     * string   $str
     * boolean  $normalizeHttp  will normalize to \ slash
     */
    function count_slashes($str, $normalizeHttp = false)
    {
        $slash = $normalizeHttp ? '\\' : '/';
        $n = 0;
        for ($i = 0; $i < strlen($str); $i++)
        { 
            if ($str[$i] == $slash)
                $n++;
        }
        return $n;
    }
    /**
     * Directory Difference
     *
     * Will find the diffrence between the document root, and the source
     * with is the relative path to this class, and return a number based
     * on the number of slashes in the string that makes up the diffrence
     *
     * string   $source
     * int      $offset     value of 1 offeset directory forward one directory 
     *                      from /HTML/foo/bar/ to /foo/bar/
     *
     */
    function dirDiff($source, $offset = 0) {
        $docRoot = str_replace('/', '\\', $_SERVER['DOCUMENT_ROOT']); // normalize to http
        $diff = str_replace($docRoot, '', $source);
        return $this->count_slashes($diff, true) - $offset; // removed ltrim to trim beginning slash of diff
    }
    /**
     *
     * zippy
     *
     * Creates a zip file from a $source directory
     * $include_dir = true means we get the parent directories up until the root directory
     *  otherwise, we just put in the $source dir and its children.
     *
     * string   $source
     * boolean  $include_dir
     *
     */
    function zippy($source, $include_dir = false)
    {
        $source = str_replace('\\', DIRECTORY_SEPARATOR, realpath($source));
        if (is_dir($source) === true) {
            $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
            // this is where we figure out where to start and how to format the directories
            if ($include_dir) {
                $goForward = $this->dirDiff($source, $this->nback);
                $arrDir = explode(DIRECTORY_SEPARATOR, $source);
                $maindir = $arrDir[count($arrDir) - $goForward];
                $this->zip->addEmptyDir($maindir);
                $source = "";
                for ($i = 0; $i < count($arrDir) - $goForward; $i++) {
                    $source .= DIRECTORY_SEPARATOR . $arrDir[$i];
                }
                $source = substr($source, 1);

            }
            foreach ($files as $file) {
                $file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
                // ignore "." and ".." folders (Note: isDot() fails to work)
                if (in_array(substr($file, strrpos($file, DIRECTORY_SEPARATOR) + 1), array('.', '..'))) {
                    continue; // exit out of loop
                }
                $file = realpath($file);
                if (is_dir($file) === true) {
                    if (!in_array(basename($file), $this->ignored_folders)) {
                        $this->zip->addEmptyDir(str_replace($source . DIRECTORY_SEPARATOR, '', $file . DIRECTORY_SEPARATOR));
                    } else {
                        continue;
                    }
                } elseif (is_file($file) === true) {
                    // for some reason addFromString iterates through dirs that are exlcuded folders
                    // so we remove ignored folders here to via a strpos hack
                    if (!in_array(basename($file), $this->ignored_files) && $this->strposArray($file, $this->ignored_folders, 1) == false) {
                        $this->zip->addFromString(str_replace($source . DIRECTORY_SEPARATOR, '', $file), file_get_contents($file));
                    } else {
                        continue;
                    }
                }
            }
        } else if (is_file($source) === true) {
            $this->zip->addFromString(basename($source), file_get_contents($source));
        }
    }
    /**
     *
     * strposArray
     *
     * Array usage of strpos
     * Returns false on first true matching result from the given array
     *
     * string           $haystack
     * string || array  $needle
     * int              $offset
     *
     */
    function strposArray($haystack, $needle, $offset= 0 ) {
        if(!is_array($needle)) {
            $needle = array($needle);
        }
        foreach($needle as $query) {
            if(strpos($haystack, $query, $offset) !== false) return true; // stop on first true result
        }
        return false;
    }
    /**
     * verifySQL
     *
     * Called to check that the $sqlDirInZip exists
     * Returns false on failure to affirm the above
     *
     */
    function verifySQL()
    {
        // the '/sql' dir exists
        // we want to use '/' instead of directory sep bc windows looks up in zips / instead of \
        if ($this->zip->statName($this->sqlDirInZip . '/') !== false) {
            return true;
        } else {
            // no sql file
            return false;
        }
    }

}

// all of the following paths in either as a destination or source can be real or absolute

$destination = 'newzippyzip.zip';
$sql = '../backup/test.sql';

if (new ZipFolder($destination, array('../images/', '../../images/uploads/'), $sql)) {
    echo 'Done!';
}

?>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM