Xóa thư mục với tập tin trong đó?


245

Tôi tự hỏi, cách dễ nhất để xóa một thư mục có tất cả các tập tin trong đó là gì?

Tôi đang sử dụng rmdir(PATH . '/' . $value);để xóa một thư mục, tuy nhiên, nếu có tệp trong đó, tôi chỉ đơn giản là không thể xóa nó.



2
yup, trả lời chính xác trong câu hỏi đó.
timdev

Chỉ muốn lưu ý. Tôi đã tạo nhiều tệp và nếu trong quá trình xử lý gặp một số lỗi, thì cần phải xóa các tệp đã tạo trước đó. Khi tạo tập tin, quên sử dụng fclose($create_file);và khi xóa, đã nhận Warning: unlink(created_file.xml): Permission denied in.... Vì vậy, để tránh các lỗi như vậy phải đóng các tập tin được tạo.
Andris

Câu trả lời:


381

Có ít nhất hai lựa chọn có sẵn hiện nay.

  1. Trước khi xóa thư mục, hãy xóa tất cả các tệp và thư mục của nó (và điều này có nghĩa là đệ quy!). Đây là một ví dụ:

    public static function deleteDir($dirPath) {
        if (! is_dir($dirPath)) {
            throw new InvalidArgumentException("$dirPath must be a directory");
        }
        if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
            $dirPath .= '/';
        }
        $files = glob($dirPath . '*', GLOB_MARK);
        foreach ($files as $file) {
            if (is_dir($file)) {
                self::deleteDir($file);
            } else {
                unlink($file);
            }
        }
        rmdir($dirPath);
    }
  2. Và nếu bạn đang sử dụng 5.2+, bạn có thể sử dụng RecursiveIterator để thực hiện mà không cần tự thực hiện đệ quy:

    $dir = 'samples' . DIRECTORY_SEPARATOR . 'sampledirtree';
    $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
    $files = new RecursiveIteratorIterator($it,
                 RecursiveIteratorIterator::CHILD_FIRST);
    foreach($files as $file) {
        if ($file->isDir()){
            rmdir($file->getRealPath());
        } else {
            unlink($file->getRealPath());
        }
    }
    rmdir($dir);

11
Việc thực hiện thứ hai của bạn hơi nguy hiểm: nó không kiểm tra các dấu chấm ( ...) và nó xóa đường dẫn đã giải quyết, chứ không phải đường dẫn thực tế.
Alix Axel

9
add-on nhỏ :-) global () không hỗ trợ các tệp như .htaccess. Tôi đã sử dụng chức năng này để xóa các thư mục được tạo bởi KC Downloader (plugin CKEditor) tạo ra cả .htaccess và .thumbs (tệp + thư mục). Thay vào đó tôi sử dụng scandirchức năng để lấy danh sách thư mục. Chỉ cần đảm bảo bạn lọc '.' và các tập tin '..' từ danh sách kết quả.
Joshua - Pendo

25
TRỰC TIẾP_SEPARATOR không cần thiết khi bạn đang xây dựng đường dẫn để gửi tới hệ điều hành. Windows cũng sẽ chấp nhận dấu gạch chéo về phía trước. Nó chủ yếu hữu ích cho explode()một đường dẫn lấy từ hệ điều hành. alanhogan.com/tips/php/directory-separator-not-n cần thiết
ReactiveRaven

5
Ngoài @Alix Axel Sử dụng ở đây, [SplFileInfo :: getRealPath ()] ( php.net/manual/en/splfileinfo.getrealpath.php ) không phải là ý kiến ​​hay. Phương pháp này mở rộng tất cả các liên kết tượng trưng, ​​có nghĩa là, sẽ bị xóa một tệp thực từ một nơi nào đó thay vào đó là một liên kết tượng trưng từ thư mục đích. Bạn nên sử dụng SplFileInfo :: getPathname ().
Vijit

2
Tôi đồng ý với @Vijit, sử dụng getPathname () thay vì getRealPath (). Nó thực hiện điều tương tự mà không xóa nhiều hơn những gì bạn đang mong đợi nếu tìm thấy liên kết tượng trưng.
JoeMoe1984

196

Tôi thường sử dụng điều này để xóa tất cả các tập tin trong một thư mục:

array_map('unlink', glob("$dirname/*.*"));

Và sau đó bạn có thể làm

rmdir($dirname);

26
Điều này không xóa các thư mục đệ quy; nó chỉ hoạt động nếu thư mục chỉ có các tệp thông thường trong đó, tất cả đều có phần mở rộng tệp.
mgnb

5
Nếu không cần đệ quy thì đây là câu trả lời tốt nhất và đơn giản nhất cho đến nay. Cảm ơn!
evdehr

2
Để xóa tất cả các tệp khỏi thư mục, không chỉ các tệp có tiện ích mở rộng, hãy sử dụng toàn cầu theo cách sau: array_map('unlink', glob("$dirname/*"));Điều này vẫn không cho phép bạn xóa các thư mục được lồng trong thư mục.
kremuwa

Lưu ý rằng điều này cũng sẽ loại bỏ các tập tin dấu chấm (ẩn).
BadHorsie

85

cách dễ nhất để xóa một thư mục có tất cả các tập tin trong đó là gì?

system("rm -rf ".escapeshellarg($dir));

33
Tôi hy vọng bạn không nghiêm túc. Điều gì xảy ra nếu $ dir là /
Nhà phát triển Pixel

108
@ Chính xác giống như với bất kỳ mã nào ở trên. Phải không?
Ý thức chung của bạn

7
Lưu ý rằng, tùy thuộc vào cách $dirtạo / cung cấp, bạn có thể cần thực hiện một số tiền xử lý bổ sung để an toàn và tránh lỗi. Ví dụ, nếu $dircó thể có một khoảng trắng không dấu hoặc nửa dấu hai chấm trong đó, thì có thể có tác dụng phụ không mong muốn. Đây không phải là trường hợp với câu trả lời sử dụng những thứ như rmdir()bởi vì nó sẽ xử lý các ký tự đặc biệt cho bạn.
Trott

5
Phiên bản Windows:system('rmdir '.escapeshellarg($path).' /s /q');
Cypher

2
@ThePixelDeveloper bạn không nên lo lắng về việc xóa /, điều này sẽ chỉ hoạt động nếu bạn liệt kê tập lệnh trong dòng lệnh dưới dạng root, bởi vì trong web mọi thứ xảy ra như người dùng apache
Ben

49

Chức năng ngắn thực hiện công việc:

function deleteDir($path) {
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

Tôi sử dụng nó trong một lớp Utils như thế này:

class Utils {
    public static function deleteDir($path) {
        $class_func = array(__CLASS__, __FUNCTION__);
        return is_file($path) ?
                @unlink($path) :
                array_map($class_func, glob($path.'/*')) == @rmdir($path);
    }
}

Với sức mạnh lớn đi kèm với trách nhiệm lớn : Khi bạn gọi hàm này với giá trị trống, nó sẽ xóa các tệp bắt đầu trong root ( /). Để bảo vệ, bạn có thể kiểm tra xem đường dẫn có trống không:

function deleteDir($path) {
    if (empty($path)) { 
        return false;
    }
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

1
Hàm tĩnh không hoạt động vì $ this === NULL khi bạn gọi hàm tĩnh trên một lớp. Nó sẽ hoạt động nếu$this_func = array(__CLASS__, __FUNCTION__);
Matt Connolly

2
Ai đó có thể giải thích dòng array_map($class_func, glob($path.'/*')) == @rmdir($path)? Tôi đoán anh ấy đang đệ quy qua các thư mục con, nhưng phần == @rmdir làm gì? Làm thế nào để <mảng booleans> == <boolean> trả về câu trả lời? Nó có kiểm tra xem mỗi giá trị trả về của đệ quy có giống với boolean bên phải không?
arviman

2
Đó là một mẹo để hợp nhất hai tuyên bố thành một tuyên bố. Điều này là do các toán tử ternary chỉ cho phép một câu lệnh cho mỗi đối số. array_map(...)xóa tất cả các tập tin trong thư mục, @rmdir(...)loại bỏ chính thư mục.
Blaise

3
Hãy cẩn thận! Hàm này không kiểm tra xem đường dẫn có thực sự tồn tại không. Nếu bạn vượt qua một đối số trống, hàm sẽ bắt đầu xóa các tệp bắt đầu từ thư mục gốc! Thêm một kiểm tra độ tỉnh táo vào đường dẫn của bạn trước khi bạn chạy chức năng này.
Tatu Ulmanen

3
Một số người không thấy bình luận của Tatu và bị xóa đệ quy /, vì vậy tôi đã thêm một phiên bản được bảo vệ vào bài đăng của mình.
Blaise

22

Như đã thấy trong hầu hết các bình luận được bình chọn trên trang hướng dẫn PHP về rmdir()(xem http://php.net/manual/es/feft.rmdir.php ), glob()hàm không trả về các tệp ẩn. scandir()được cung cấp như là một giải pháp thay thế giải quyết vấn đề đó.

Thuật toán được mô tả ở đó (hoạt động như một bùa mê trong trường hợp của tôi) là:

<?php 
    function delTree($dir)
    { 
        $files = array_diff(scandir($dir), array('.', '..')); 

        foreach ($files as $file) { 
            (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); 
        }

        return rmdir($dir); 
    } 
?>

bạn có thể vui lòng giải thích is_dir ("$ dir / $ file") - không đáp ứng với tham số "$ dir / $ file"
Igor L.

Ý anh là gì? Nó kiểm tra xem mục nhập được tìm thấy trong một thư mục ( $file) là một thư mục hoặc một tệp. "$dir/$file"cũng giống như $dir . "/" . $file.
Latorre Đức

Tôi thực sự không biết bạn có thể ghép các biến như thế này :) thx
Igor L.

18

Đây là một phiên bản ngắn hơn hoạt động tuyệt vời với tôi

function deleteDirectory($dirPath) {
    if (is_dir($dirPath)) {
        $objects = scandir($dirPath);
        foreach ($objects as $object) {
            if ($object != "." && $object !="..") {
                if (filetype($dirPath . DIRECTORY_SEPARATOR . $object) == "dir") {
                    deleteDirectory($dirPath . DIRECTORY_SEPARATOR . $object);
                } else {
                    unlink($dirPath . DIRECTORY_SEPARATOR . $object);
                }
            }
        }
    reset($objects);
    rmdir($dirPath);
    }
}

15

Bạn có thể sử dụng Symfony's Filesystem ( ):

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

(new Filesystem)->remove($dir);

Tuy nhiên tôi không thể xóa một số cấu trúc thư mục phức tạp bằng phương pháp này, vì vậy trước tiên bạn nên thử nó để đảm bảo nó hoạt động tốt.


Tôi có thể xóa cấu trúc thư mục đã nói bằng cách sử dụng Windows cụ thể:

$dir = strtr($dir, '/', '\\');
// quotes are important, otherwise one could
// delete "foo" instead of "foo bar"
system('RMDIR /S /Q "'.$dir.'"');


Và chỉ để hoàn thiện, đây là một mã cũ của tôi:

function xrmdir($dir) {
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $path = $dir.'/'.$item;
        if (is_dir($path)) {
            xrmdir($path);
        } else {
            unlink($path);
        }
    }
    rmdir($dir);
}

Cảm ơn rất nhiều. Bạn tiết kiệm thời gian của tôi.
zarif khan

"Đừng phát minh lại bánh xe" . Cảm ơn bạn
Kamafeather

9

Ở đây bạn có một đệ quy đẹp và đơn giản để xóa tất cả các tệp trong thư mục nguồn bao gồm thư mục đó:

function delete_dir($src) { 
    $dir = opendir($src);
    while(false !== ( $file = readdir($dir)) ) { 
        if (( $file != '.' ) && ( $file != '..' )) { 
            if ( is_dir($src . '/' . $file) ) { 
                delete_dir($src . '/' . $file); 
            } 
            else { 
                unlink($src . '/' . $file); 
            } 
        } 
    } 
    closedir($dir); 
    rmdir($src);

}

Chức năng dựa trên đệ quy được thực hiện để sao chép thư mục. Bạn có thể tìm thấy chức năng đó tại đây: Sao chép toàn bộ nội dung của một thư mục sang thư mục khác bằng php


4

Giải pháp tốt nhất cho tôi

my_folder_delete("../path/folder");

mã:

function my_folder_delete($path) {
    if(!empty($path) && is_dir($path) ){
        $dir  = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS); //upper dirs are not included,otherwise DISASTER HAPPENS :)
        $files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($files as $f) {if (is_file($f)) {unlink($f);} else {$empty_dirs[] = $f;} } if (!empty($empty_dirs)) {foreach ($empty_dirs as $eachDir) {rmdir($eachDir);}} rmdir($path);
    }
}

NHỚ NHỚ!
không chuyển GIÁ TRỊ EMPTY cho bất kỳ chức năng xóa thư mục nào !!! (luôn luôn sao lưu chúng, nếu không một ngày nào đó bạn có thể bị DISASTER !!)


4

Cái này thì sao:

function recursiveDelete($dirPath, $deleteParent = true){
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) {
        $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname());
    }
    if($deleteParent) rmdir($dirPath);
}

4

Hàm Glob không trả về các tệp bị ẩn, do đó scandir có thể hữu ích hơn khi cố gắng xóa đệ quy một cây.

<?php
public static function delTree($dir) {
   $files = array_diff(scandir($dir), array('.','..'));
    foreach ($files as $file) {
      (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
    }
    return rmdir($dir);
  }
?>

4

Bạn có thể thử như sau:

/*
 * Remove the directory and its content (all files and subdirectories).
 * @param string $dir the directory name
 */
function rmrf($dir) {
    foreach (glob($dir) as $file) {
        if (is_dir($file)) { 
            rmrf("$file/*");
            rmdir($file);
        } else {
            unlink($file);
        }
    }
}

3

Tôi thích điều này bởi vì nó vẫn trả về TRUE khi nó thành công và FALSE khi nó thất bại, và nó cũng ngăn một lỗi trong đó một đường dẫn trống có thể thử và xóa mọi thứ từ '/ *' !!:

function deleteDir($path)
{
    return !empty($path) && is_file($path) ?
        @unlink($path) :
        (array_reduce(glob($path.'/*'), function ($r, $i) { return $r && deleteDir($i); }, TRUE)) && @rmdir($path);
}

3

Tôi muốn mở rộng câu trả lời của @alcuadrado với nhận xét của @Vijit để xử lý các liên kết tượng trưng. Đầu tiên, sử dụng getRealPath (). Nhưng sau đó, nếu bạn có bất kỳ liên kết tượng trưng nào là thư mục thì nó sẽ thất bại vì nó sẽ thử và gọi rmdir trên một liên kết - vì vậy bạn cần kiểm tra thêm.

$it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
foreach($files as $file) {
    if ($file->isLink()) {
        unlink($file->getPathname());
    } else if ($file->isDir()){
        rmdir($file->getPathname());
    } else {
        unlink($file->getPathname());
    }
}
rmdir($dir);

1
Tôi không có đủ đại diện để bình luận về câu trả lời trực tiếp.
dùng701152

3

Sử dụng DirectoryIterator tương đương với câu trả lời trước đó

function deleteFolder($rootPath)
{   
    foreach(new DirectoryIterator($rootPath) as $fileToDelete)
    {
        if($fileToDelete->isDot()) continue;
        if ($fileToDelete->isFile())
            unlink($fileToDelete->getPathName());
        if ($fileToDelete->isDir())
            deleteFolder($fileToDelete->getPathName());
    }

    rmdir($rootPath);
}

3

Cái này hoạt động với tôi:

function removeDirectory($path) {
    $files = glob($path . '/*');
    foreach ($files as $file) {
        is_dir($file) ? removeDirectory($file) : unlink($file);
    }
    rmdir($path);
    return;
}

2

Một cái gì đó như thế này?

function delete_folder($folder) {
    $glob = glob($folder);
    foreach ($glob as $g) {
        if (!is_dir($g)) {
            unlink($g);
        } else {
            delete_folder("$g/*");
            rmdir($g);
        }
    }
}

2

Sửa đổi tiêu đề bit của mã alcuadrado - globkhông thấy các tệp có tên từ các điểm như .htaccessvậy nên tôi sử dụng scandir và script tự xóa - kiểm tra __FILE__.

function deleteDir($dirPath) {
    if (!is_dir($dirPath)) {
        throw new InvalidArgumentException("$dirPath must be a directory");
    }
    if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
        $dirPath .= '/';
    }
    $files = scandir($dirPath); 
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        if (is_dir($dirPath.$file)) {
            deleteDir($dirPath.$file);
        } else {
            if ($dirPath.$file !== __FILE__) {
                unlink($dirPath.$file);
            }
        }
    }
    rmdir($dirPath);
}

2

Ví dụ cho máy chủ Linux: exec('rm -f -r ' . $cache_folder . '/*');


Tôi thường muốn thêm kiểm tra độ tỉnh táo trên $ cache_folder trước khi chạy rm -rf để tránh những sai lầm tốn kém
glyph

1

Xóa tất cả các tệp trong Thư mục
array_map('unlink', glob("$directory/*.*"));
Xóa tất cả. * - Các tệp trong Thư mục (không có: "." Và "..")
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
Bây giờ hãy xóa chính Thư mục
rmdir($directory)


1

2 xu để thêm vào câu trả lời NÀY ở trên, đó là BTW tuyệt vời

Sau khi chức năng toàn cầu (hoặc tương tự) của bạn đã quét / đọc thư mục, hãy thêm một điều kiện để kiểm tra phản hồi không trống, hoặc một invalid argument supplied for foreach()cảnh báo sẽ được đưa ra. Vì thế...

if( ! empty( $files ) )
{
    foreach( $files as $file )
    {
        // do your stuff here...
    }
}

Hàm đầy đủ của tôi (như một phương thức đối tượng):

    private function recursiveRemoveDirectory( $directory )
    {
        if( ! is_dir( $directory ) )
        {
            throw new InvalidArgumentException( "$directory must be a directory" );
        }

        if( substr( $directory, strlen( $directory ) - 1, 1 ) != '/' )
        {
            $directory .= '/';
        }

        $files = glob( $directory . "*" );

        if( ! empty( $files ) )
        {
            foreach( $files as $file )
            {
                if( is_dir( $file ) )
                {
                    $this->recursiveRemoveDirectory( $file );
                }
                else
                {
                    unlink( $file );
                }
            }               
        }
        rmdir( $directory );

    } // END recursiveRemoveDirectory()

1

Đây là giải pháp hoạt động hoàn hảo:

function unlink_r($from) {
    if (!file_exists($from)) {return false;}
    $dir = opendir($from);
    while (false !== ($file = readdir($dir))) {
        if ($file == '.' OR $file == '..') {continue;}

        if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
            unlink_r($from . DIRECTORY_SEPARATOR . $file);
        }
        else {
            unlink($from . DIRECTORY_SEPARATOR . $file);
        }
    }
    rmdir($from);
    closedir($dir);
    return true;
}

1

Bạn có thể sao chép người trợ giúp YII

$ thư mục (chuỗi) - sẽ bị xóa đệ quy.

$ tùy chọn (mảng) - để loại bỏ thư mục. Các tùy chọn hợp lệ là: traverseSymlinks: boolean, cho dù các liên kết đến các thư mục cũng nên được duyệt qua. Mặc định false, có nghĩa là nội dung của thư mục symlinked sẽ không bị xóa. Chỉ symlink sẽ bị xóa trong trường hợp mặc định đó.

public static function removeDirectory($directory,$options=array())
{
    if(!isset($options['traverseSymlinks']))
        $options['traverseSymlinks']=false;
    $items=glob($directory.DIRECTORY_SEPARATOR.'{,.}*',GLOB_MARK | GLOB_BRACE);
    foreach($items as $item)
    {
        if(basename($item)=='.' || basename($item)=='..')
            continue;
        if(substr($item,-1)==DIRECTORY_SEPARATOR)
        {
            if(!$options['traverseSymlinks'] && is_link(rtrim($item,DIRECTORY_SEPARATOR)))
                unlink(rtrim($item,DIRECTORY_SEPARATOR));
            else
                self::removeDirectory($item,$options);
        }
        else
            unlink($item);
    }
    if(is_dir($directory=rtrim($directory,'\\/')))
    {
        if(is_link($directory))
            unlink($directory);
        else
            rmdir($directory);
    }
}

0
<?php
  function rrmdir($dir) {
  if (is_dir($dir)) {
    $objects = scandir($dir);
    foreach ($objects as $object) {
      if ($object != "." && $object != "..") {
        if (filetype($dir."/".$object) == "dir") 
           rrmdir($dir."/".$object); 
        else unlink   ($dir."/".$object);
      }
    }
    reset($objects);
    rmdir($dir);
  }
 }
?>

Bạn đã thử mã trên từ php.net chưa

Làm việc tốt cho tôi


0

Cho cửa sổ:

system("rmdir ".escapeshellarg($path) . " /s /q");

0

Giống như giải pháp của Playnox, nhưng với DirectoryIterator tích hợp sẵn thanh lịch:

function delete_directory($dirPath){
 if(is_dir($dirPath)){
  $objects=new DirectoryIterator($dirPath);
   foreach ($objects as $object){
    if(!$object->isDot()){
     if($object->isDir()){
      delete_directory($object->getPathname());
     }else{
      unlink($object->getPathname());
     }
    }
   }
   rmdir($dirPath);
  }else{
   throw new Exception(__FUNCTION__.'(dirPath): dirPath is not a directory!');
  }
 }

0

Tôi không nhớ nơi tôi đã sao chép chức năng này, nhưng có vẻ như nó không được liệt kê và nó hoạt động với tôi

function rm_rf($path) {
    if (@is_dir($path) && is_writable($path)) {
        $dp = opendir($path);
        while ($ent = readdir($dp)) {
            if ($ent == '.' || $ent == '..') {
                continue;
            }
            $file = $path . DIRECTORY_SEPARATOR . $ent;
            if (@is_dir($file)) {
                rm_rf($file);
            } elseif (is_writable($file)) {
                unlink($file);
            } else {
                echo $file . "is not writable and cannot be removed. Please fix the permission or select a new path.\n";
            }
        }
        closedir($dp);
        return rmdir($path);
    } else {
        return @unlink($path);
    }
}

0

Đơn giản và dễ dàng...

$dir ='pathtodir';
if (is_dir($dir)) {
  foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
    if ($filename->isDir()) continue;
    unlink($filename);
  }
  rmdir($dir);
}


0

Nếu bạn không chắc chắn, đường dẫn đã cho là thư mục hoặc tệp thì bạn có thể sử dụng chức năng này để xóa đường dẫn

function deletePath($path) {
        if(is_file($path)){
            unlink($path);
        } elseif(is_dir($path)){
            $path = (substr($path, -1) !== DIRECTORY_SEPARATOR) ? $path . DIRECTORY_SEPARATOR : $path;
            $files = glob($path . '*');
            foreach ($files as $file) {
                deleteDirPath($file);
            }
            rmdir($path);
        } else {
            return false;
        }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.