Using command – DirManager class

Mấy hôm trước lại được làm 1 task liên quan đến thao tác với thư mục bằng PHP 🙂 Thật ra trước đó đã từng làm rồi nhưng giờ vẫn khoái…viết lại, bởi quan trọng nhất là cái class đó…không còn trong máy tính ở cty nữa :)) Ở nhà thì ko tiện remote connect vào (có ai mở hộ máy đâu mà vào :-p) nên quyết định viết lại & phải chạy được cả trên Unix & Windows.

Class DirManager tạm thời có mấy method sau:

operaSystem = $_SERVER['SERVER_SOFTWARE'];

           if(stripos($this->operaSystem, 'Win32')) {
                return false;
           }

            return true;
        }

        /**
         * Create directory
         * @param string folderName
         */
        public function createDir() {
            if(!is_dir($this->sourcePath)) {
                if(!mkdir($this->sourcePath, 0777)) {
                   die('Could not create sub-domain.');
                }
            }
            else {
                die($this->sourcePath.' is exist.');
            }
        }

        /**
         * copy using php function
         * @param string source
         * @param string dest
         */
        private function windowsCopyDir($source, $dest)
        {
            if(!is_dir($dest)) {
                mkdir($dest, 0777);
            }
            if($curdir = opendir($source)) {
                while($file = readdir($curdir)) {
                    if($file != '.' && $file != '..') {
                        $srcfile = $source . '/' . $file;
                        $dstfile = $dest . '/' . $file;

                        if(is_file($srcfile)) {
                            copy($srcfile, $dstfile);
                        }
                        else if(is_dir($srcfile)) {
                            $this->windowsCopyDir($srcfile, $dstfile);
                        }
                    }
              }
              closedir($curdir);
            }
        }

        /**
         * Copy directory and all sub directory in it
         * @param bool useCommand
         */
        public function copyDir($useCommand=true) {
            if(is_dir($this->sourcePath)) {
                if($this->isLinuxOS()) {
                    if($useCommand) {
                        exec("cd {$this->sourcePath}; shopt -s dotglob; cp -pr . {$this->destinationPath}");
                    }
                    else {
                        $this->WindowsCopyDir($this->sourcePath, $this->destinationPath);
                    }
                 }
                 else {
                    if($useCommand) {
                        exec("xcopy {$this->sourcePath} {$this->destinationPath} /E");
                    }
                    else {
                        $this->WindowsCopyDir($this->sourcePath, $this->destinationPath);
                    }
                 }
            }
            else {
                die($this->sourcePath.' is not a directory.');
            }
        }

        /**
         * Remove directory and all sub directory in it
         * @param bool useCommand
         */
        public function removeDir($useCommand=false) {
            if(is_dir($this->sourcePath)) {
                if($this->isLinuxOS()) {
                    if($useCommand) {
                        exec("rm -rf {$this->sourcePath} {$this->destinationPath}");
                    }
                    else {
                        $this->windowsRemoveDir($this->sourcePath);
                    }
                }
                else {
                    if($useCommand) {
                        exec("DELLTREE {$this->sourcePath}");
                    }
                    else {
                        $this->windowsRemoveDir($this->sourcePath);
                    }
                }
            }
            else {
                die($this->sourcePath.' is not a directory.');
            }
        }

        /**
         * @param string source folder to delete
         * @param int level
         */
        private function windowsRemoveDir($source, $level=0) {
            // Trim the trailing slash
            $source = preg_replace("|^(.+?)/*$|", "\\1", $source);

            if(is_dir($source)) {
                if ( ! $current_dir = @opendir($source))
                    return;

                while(FALSE !== ($filename = @readdir($current_dir))) {
                    if ($filename != "." && $filename != "..") {
                        if (is_dir($source.'/'.$filename)) {
                            $this->windowsRemoveDir($source.'/'.$filename, $level + 1);
                        }
                        else {
                            unlink($source.'/'.$filename);
                        }
                    }
                }

                @closedir($current_dir);
                @rmdir($source);
            }
            else {
                unlink($source);
            }
        }
    }
?>

Đoạn code trên chắc chắn với những lập trình viên có kinh nghiệm hay nói cách khác là trình độ, họ sẽ khẽ mĩm cười & chẳng nói gì đâu. Còn nhiều vấn đề. Tôi cũng biết điều đó 🙁 Viết OOP không phải cứ quẳng 1 đống hàm vào trong class thì nó là OOP 😥 Nhưng, tạm thời đến lúc này trình độ của tôi chỉ có vậy. Sẽ còn phải cố nhiều đây :clown:

Một điểm thú vị khi viết method copyDir đó là nếu set $useCommand = true, tức là sử dụng command line để copy files & folders (nhanh hơn là dùng PHP để đọc & copy), nếu chạy trên Windows, okie, chạy tốt (trên máy của tôi :p), còn trên Linux thì nó lại copy nguyên cái thư mục nguồn vào bên trong thư mục đích. Cái tôi cần ở đây là chỉ copy các file & folder ở bên trong thư mục nguồn vào thư mục đích.

Và tôi sai ở đây:

exec("cp -pr {$this->sourcePath} {$this->destinationPath}");

Đúng ra phải là:

exec("cd {$this->sourcePath}; shopt -s dotglob; cp -pr . {$this->destinationPath}");

Tức là:
– Set thư mục nguồn làm thư mục gốc (nhảy vào bên trong thư mục nguồn).
– Hiện tất cả file ẩn.
– Copy tất cả file & folder ở thư mục gốc vào thư mục đích

=> Chạy rất nuột :p

$dirObj = DirManager::getInstance();
$dirObj->sourcePath      = 'foo';
$dirObj->destinationPath = 'bar';
$dirObj->copyDir();

Toàn bộ đám bậu sậu trong foo đã nằm trọn trong vòng tay của bar :p

Posted in PHP
It's me ;-)

Nam Khanh Do

Khanh is a full stack web developer with over 10 years of experience developing for the web. You can reach him on Twitter, like him on Facebook and connect with him on LinkedIn.

7 thoughts on “Using command – DirManager class

  1. Ây chà, hoàng tử đến chơi nhà 😀

    Vậy phải viết thêm 1 đoạn (method?) để xác định xem SafeMode có bật không nhỉ? Nếu bật thì dùng build in PHP function để copy, remove 🙂

  2. Theo tớ thì nên dùng các hàm của FTP để thực hiện các công việc make dir, copy, chmod khi đó file và thư mục được tạo ra sẽ đúng user,group và sẽ không vướng phải các vấn đề về permission !

  3. Blog này có captcha thuần việt ghê 😀
    Tớ lưu ý thêm là nếu dùng các hàm build in của php thì thư mục hay file được tạo ra sẽ thuộc quyền sở hữu của apache sẽ gây lôi permission nên phải dùng FTP để đúng quyền sở hũư 😉

  4. Hehe…thanks lời khen về cái captcha :p

    Đúng như cậu nói, cách ổn nhất có lẽ là dùng ftp functions để giữ được đúng owner, cái này quan trọng nhất đấy 😀

  5. Pingback: tinh

Leave a Reply to Đoàn Đức Cancel reply

Your email address will not be published. Required fields are marked *