【问题标题】:creating a backup using php on localhost and server在本地主机和服务器上使用 php 创建备份
【发布时间】:2014-10-19 10:44:44
【问题描述】:

我创建了自己的备份系统,用于备份我的数据库和网站上可能发生更改的各种文件夹(为简单起见,假设一个文件夹 -> folder_to_backup 以及我想要保留的文件和文件夹)。唯一的问题是,它不适用于本地环境(localhost),这是我想解决的问题。这是执行实际压缩的类(忘记我从哪里得到它):

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

因此,我使用上面的代码创建了我的 zip 文件,但是我必须发送 $folderrealpath() 以使迭代器工作,因此在本地环境中我会得到这样的结果:

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

在 http 环境中:

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

假设我想更新我的站点的本地主机副本,我下载了文件,但由于目录结构不兼容,我无法解压缩它,目录分隔符也不兼容。

所以我想我可以隔离'cms' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'folder_to_backup 的共同点。所以本质上不是让所有文件夹通向文件夹 cms 我只会有结构

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

然后在还原时,而不是通过realpath(DIRECTORY_SEPARATOR) 将其提取到/opt/C:\。我会使用类似于realpath(dirname(__FILE__)) 的东西或者你有什么。

简而言之,我的问题是如何获得上述文件结构(不包括直到/files/ 的真实路径,知道我必须为 zip 创建者提供真实路径以便它可以找到文件?

【问题讨论】:

    标签: php iterator directory zip


    【解决方案1】:

    使用这个脚本:

    1) 如果您的网站很大并且需要很长时间进行备份,则将执行时间设置为 0,因为 PHP 的默认执行时间是 30 秒。

    ini_set("max_execution_time", 0);
    

    2) 通过使用下面的代码,我们正在创建一个目录,您将在其中存储您的 zip。就我而言,我的目录名称是“site-backup-stark”。

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

    3) 设置您的站点凭据。

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

    4) 我们将以 zip 格式保存备份,因此创建一个 zip 对象。

    $zip = new ZipArchive();
    

    5) 调用函数backup_tables。

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

    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) 将 .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) 现在我们必须获取我们的 php 文件所在的当前文件夹名称。这是因为当我们必须将所有文件夹和文件从根目录移动到我们的 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) 为 zip 文件创建一个名称。我根据今天的日期创建了它,以便我们可以轻松找到上次备份的日期。此外,我将“stark-”附加到我们在接下来的过程中使用的 zip 文件的名称中。

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

    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) 从根目录中删除所有 .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) 现在将 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) 从根目录中删除一个 zip 文件,因为我们将它移动到另一个目录中。

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

    【讨论】:

    • 感谢您花时间编写所有这些,看来我们甚至使用了类似的方式来备份数据库。但是无论如何,我正在寻找我的特定问题的答案,而不是另一种方法,因为我可以为我的脚本指定目录,你只需压缩整个根目录
    • 也直接复制自:starkdigital.net/…
    【解决方案2】:

    所以,因为我找不到直接的答案,而且一无所获,我在这个网站上做了很多研究,并通过查找其他备份方法,我开始创建一个类,它结合了许多与堆栈相关的答案将此归为一类。我什至添加了一种忽略文件和文件夹的方法,以及一种自动查找实际 zi​​p 架构应该从哪个目录开始的方法。我已经确认它可以在 Windows(通过 xampp)和我的站点服务器上运行。希望这可以避免一些人头疼!

    课程结束时概述的用法!如果有人想重构它,请随意,但请对其进行测试,然后更新我的答案!

    <?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!';
    }
    
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-12
      • 2019-03-10
      • 2013-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多