Преброяване на файловете в директория и качване на файлове

nom3r1

Registered
@admin, ми даде един съвет относно качването на снимки при сайтове/ако се очаква да се качват разбира се/.

Така.

Опитах се да създам сам кода, но стават все не сполучливи неща.

Идеята е следната. Ако upload директорията има над 1000 файла да се създава нова папка и в нея да се качват новите файлове, ако вече и в нея има над 1000 файла, то тогава отново да се създава нова папка.

Тоест.

upload/1/
upload/2/
upload/3/
...

И друго важно нещо.
Не може да имаш 20000 снимки в една директория.
Ще скапеш сървърът.
Или 100000 или 1000000.
Товари дзверски.
Питай някой и ще видиш.
В туриста има система да се качват в
/images/1/ - 1000 файла
/images/2/ - 1000 файла
....

Опитах се да напиша кода, но без успех.

Първия код, които ми хрумна снощи беше:

PHP:
<?php
$path = "upload/";
if (!is_writeable("$path")){
	echo "Грешка: Промени правомощията на папката.";
} else {
	if(!is_dir("$path")) {
		echo "Главната директория не съществува.";
	} else {
		$directory = scandir($path);
		$directory = array_diff($directory, array('.','..'));
		$dir_count = count($directory);
		if($dir_count > 1000) {
			mkdir("upload/1", 777, true);
			//upload
		} else {
			//upload
		}
	}
}
?>

Какво имаме? Проверяваме правомощията на папката, проверяваме дали съществува, сканираме е за да преброим файлове, ако върне по-голям резултат от 1000 да създаде папка upload/2

и да качи файла в тази директория. Хубаво, но ако въпросната директория бъде с 1000 снимки, то тогава ще трябва да създам и в нея една проверка може би:

PHP:
<?php
$path = "upload/";
if (!is_writeable("$path")){
	echo "Грешка: Промени правомощията на папката.";
} else {
	if(!is_dir("$path")) {
		echo "Главната директория не съществува.";
	} else {
		$directory = scandir($path);
		$directory = array_diff($directory, array('.','..'));
		$dir_count = count($directory);
		if($dir_count > 1000) {
			mkdir("upload/1", 777, true);
			$directory = scandir("upload/1");
			$directory = array_diff($directory, array('.','..'));
			$dir_count = count($directory);
			if($dir_count > 1000) {
				mkdir("upload/2", 777, true);
				//upload
			} else {
				//upload
			}
		} else {
			//upload
		}
	}
}
?>

От което се губи целия смисъл.

Мислех да използвам for() за целта, но така ще създавам въпросните папки без въобще да се прави проверка дали има файлове във въпросните папки и те ще си бъдат празни..

PHP:
<?php
for ($i=0; $i<=15; $i++) {
    mkdir(dechex($i),0755);

}
?>

Очаквам предложения и примери. :)
 
Обмислял ли си варианта да записваш информация за файловете в база данни ? Или да имаш файл, който ти съдържа броя на папките и броя на файловете в последната папка. И правиш проверка там, при което след всяко качване на файл, записваш новата информация във файла с информация за папките :)
 
HerpaMoTeH каза:
Обмислял ли си варианта да записваш информация за файловете в база данни ? Или да имаш файл, който ти съдържа броя на папките и броя на файловете в последната папка. И правиш проверка там, при което след всяко качване на файл, записваш новата информация във файла с информация за папките :)

Записвам имената на въпросните файлове, но не и въпросната им бройка. Мисля, че може да стане и без MySQL - би трябвало.
 
Ето ти идеята ми в примери:
Dir/
-upload1/
--file1
--file2
--file3
...
--file999
-upload2/
--file1
--file2
--file3
--file4
-info.txt


Последния файл ти е файла с информацията. Неговото съдърание в случая ще е:
2,4

В PHP ще взимаш така информацията:
PHP:
$info_file=fopen("Dir/info.txt");
$info=explode(",",$info_file);
$papka=$info[0];
$broi_failove_v_papka=$info[1];
//upload
//kato zapisva6 v papka pravi6 stringa taka
$path="upload".$info[0];
//krai na upload
if($info[1]>1000){
 $info[0]++;
 $info[1]=0;
}else{
 $info[1]++;
}
$string_to_write=$info[0].",".$info[1];
fwrite($string_to_write,$info_file);
 
Какъв е смисъла да записвам номера/броя/ на снимките , като мога с count(); да ги преброя?

Точно това и правя със следния if();

PHP:
$dir_count = count($directory);
 if($dir_count > 1000) {
//ако е повече от 1000 да създава новата папка и да качва файловете в нея
} else {
//качване на снимката в сегашната папка, тъй като не надвишава 1000 файла
}
 
Като си записваш броя, после го проверяваш и така имаш броя само на снимките само в папката, в която вече трябва да записваш. Иначе другия вариант е само да си записваш броя на папките и после с един цикъл да ги обхождаш и да търсиш свободна папка и ако няма такава да правиш нова папка.
 
HerpaMoTeH каза:
Иначе другия вариант е само да си записваш броя на папките и после с един цикъл да ги обхождаш и да търсиш свободна папка и ако няма такава да правиш нова папка.

Точно това нямам на идея как ще стане, тъй като почти никога не ми се е налагало да работя с папки/файлове.

Между другото, това със записването на номера в края на снимката го "отлагам", 'щото вече имам към 500 снимки със уникални имена/не повтарящи/ също така са записани и в база от данни. Ще си падне играчка да ги преправя.

PHP:
<?php
error_reporting(E_ALL);
ini_set("display_errors", true);
$path = "upload/";
if(!is_dir("$path")) {
	echo "Главната директория не съществува.";
} else {
	if (!is_writeable("$path")){
		echo "Грешка: Промени правомощията на папката.";
	} else {
		$directory = scandir($path);
		$directory = array_diff($directory, array('.','..','.htaccess'));
		$dir_count = count($directory);
		for($i = 1; $i < $dir_count; $i ++) {
			echo $i;
		}
		/*
		print_r($directory);
		
		резултат от echo $i; ==>	1234
		резултат от print_r ==>
		Array
		(
			[2] => 1
			[3] => 2
			[4] => 3
			[5] => 4
			[6] => 5
		)
		съдържание в папка upload/ ===>
		папки с имена: 1, 2, 3, 4, 5
		*/
	}
}
?>

Това е за което се сещам.. в крайна сметка след теста, ми изброява файловете в директорията. Сега трябва да им взема имената и да направя проверка с is_dir(); дали е папка или файл.

След, което проверката дали файловете в дадената директория са надминали 1000 файла/снимки/ и ако не са записвам снимката там, в противен случай създавам нова директория.
 
Идеята е следната имаш една папка uploads (в която слагаш images0, images1, images2, images3, images4... и т.н, може и .htaccess, но за предпочитане е да няма други файлове, а ако имаш да ги сложиш в $exclude масива).

1. Стъпка: След това преброяваш файловете в тази папка (като благодарение на горните условия си сигурен, че са папки). Ако искаш да слагаш и други неща в uploads, които не можеш да изредиш в $exclude масива, тогава ще трябва да завъртиш един foreach, в който да проверяваш дали файлът е папка и ако е да добавяш 1 към дадена променлива. Така получава променлива $count_dirs

2. Стъпка: Като си получил $count_dirs си вече готов да обходиш въпросните папки. Пускаш един for цикъл, който ще продължава да се върти докато стигнеш и до последната папка imagesN

3. Стъпка: Това е най-важната част. Тук правиш проверка. В първата част на условието проверяваш дали в текущата папка имаш 1000 или повече файла и втората част (която ще обясня в стъпка 4). Ако и двете условия върнат true - тогава създаваш нова папка, ако едното се провали ще продължиш да въртиш цикъла for, докато не влезеш в подходяща папка (или си създадеш такава).

4. Стъпка: Това е много съществена част от проверката. Ще ти я обясня с пример:
images - 1000 файла
images1 - 500 файла
Ако пропуснеш втората проверка for цикълът ще влезе в images0 ще види, че има 1000 файла и ще създаде images2 (а ти не искаш това - искаш да влезе в папка images1 - той ще влезе в нея де, но ще създадеш и нова излишна папка).
Това нали изглежда незначителен проблем, но ще се случва винаги и с нарастването на папките ще се увеличава.

Втората проверка просто проверява дали си в края на цикъла и ако си чак тогава създава нова папка, а ако не си прескача if проверката и започва отначало.

Малко дървено го обясних, ама работи (като изключим ограничението в началото, но можеш да си го оправиш :))

PHP:
<?php

$path = 'uploads/'; // пълен път до папката, в която ще качваш файлове
$exclude = array('.', '..', '.htaccess'); 
$max_files = 1000;


$dirs = scandir($path); 
$dirs = array_diff($dirs, $exclude); 
$count_dirs = count($dirs); // броя на папките в uploads/ (хубаво е там да имаш само папки, за да не прецакаш скрипта, защото не съм добавял проверки и за това)
$dirs_keys = array_keys($dirs); // взимаме ключовете на масива, защото не винаги започват от 1

chdir($path); // задаваме пътя да е пътят до папката, за да не се налага да го пишем, като правим mkdir

for($i = 1; $i <= $count_dirs; $i++) {
    
    $current_folder = scandir($dirs[$dirs_keys[$i-1]]);
    $current_folder = array_diff($current_folder, $exclude);
    $count_files = count($current_folder);
    
    if($count_files >= $max_files and $count_dirs <= $i) {
        mkdir('images'.$i);
    }

}
?>


EDIT: С долния код се премахва проблема с ограничаването в папка uploads да нямаш нищо друго освен images0 ... imagesN.
С долната поправка хубавото е, че можеш дори да имаш и други папки, просто не трябва името им да започва с images0. Можеш да видиш функцията, която направи това glob()

PHP:
<?php

$path = 'uploads/'; // пълен път до папката, в която ще качваш файлове
$exclude = array('.', '..', '.htaccess'); 
$max_files = 1000;

chdir($path); /* задаваме пътя да е пътят до папката, за да не се налага да го пишем, като правим mkdir, а и за да знае къде да търси glob(), защото иначе ползва текущата директория, откъдето е стартиран скрипта */

$dirs = glob("images*", GLOB_ONLYDIR); 
$dirs = array_diff($dirs, $exclude);  // този ред в случая е напълно излишен, защото glob се грижи да не върне и '.', '..'
$count_dirs = count($dirs); // тук вече си сигурен, че си взел само необходимите папки, благодарение на glob()

for($i = 1; $i <= $count_dirs; $i++) {
    
    $current_folder = scandir($dirs[$i-1]);
    $current_folder = array_diff($current_folder, $exclude);
    $count_files = count($current_folder);
    
    if($count_files >= $max_files and $count_dirs <= $i) {
        mkdir('images'.$i);
    }

}
?>

Благодарение на този код получаваш структура от вида:

uploads/
-images0/
-images1/
-images2/
....
-imagesN/

Като задължително е папка images0 да си я създадеш ти ръчно, което не е кой знае какъв проблем :)


А в $uploaded_dir си запазваш път към папката, в която ще качваш файловете (по подразбиране от скрипта ще е images0, но като се напълни, той сам ще си създава нови):

PHP:
<?php

$path = 'uploads/'; // пълен път до папката, в която ще качваш файлове
$exclude = array('.', '..', '.htaccess'); 
$max_files = 1000;
$uploaded_dir = 'images0/';

chdir($path); /* задаваме пътя да е пътят до папката, за да не се налага да го пишем, като правим mkdir, а и за да знае къде да търси glob(), защото иначе ползва текущата директория, откъдето е стартиран скрипта */

$dirs = glob("images*", GLOB_ONLYDIR); 

$dirs = array_diff($dirs, $exclude);  // този ред в случая е напълно излишен, защото glob се грижи да не върне и '.', '..'
$count_dirs = count($dirs); // тук вече си сигурен, че си взел само необходимите папки, благодарение на glob()

for($i = 1; $i <= $count_dirs; $i++) {
    
    $current_folder = scandir($dirs[$i-1]);
    $current_folder = array_diff($current_folder, $exclude);
    $count_files = count($current_folder);
    
    if($count_files >= $max_files and $count_dirs <= $i) {
        mkdir('images'.$i);
		$uploaded_dir = 'images'.$i.'/';
    } else {
		$ii = $i-1;
		$uploaded_dir = 'images'.$ii.'/';
	}

}

?>

Малък недостатък е, че ако имаш:

images0 - 1000 файла
images1 - 1000 файла
images2 - 500 файла

и решиш в images 0 да изтриеш 10 файла - като почнеш да качваш снимки наново няма да се качат в images0, а ще продължат в images2, но това не е болка за умиране... може да се оправи и това, ама вече не ми се мисли в тази насока :)


LAST EDIT: Добавих още едно else if условие, което поправя горния проблем. Т.е в някоя от предходните папки ако се освободи място - веднага се заема и чак след това почват да се запълват следващи папки :)

PHP:
<?php

$path = 'uploads/'; // пълен път до папката, в която ще качваш файлове
$exclude = array('.', '..', '.htaccess'); 
$max_files = 1000;
$uploaded_dir = 'images0/';

chdir($path); /* задаваме пътя да е пътят до папката, за да не се налага да го пишем, като правим mkdir, а и за да знае къде да търси glob(), защото иначе ползва текущата директория, откъдето е стартиран скрипта */

$dirs = glob("images*", GLOB_ONLYDIR); 

$dirs = array_diff($dirs, $exclude);  // този ред в случая е напълно излишен, защото glob се грижи да не върне и '.', '..'
$count_dirs = count($dirs); // тук вече си сигурен, че си взел само необходимите папки, благодарение на glob()


for($i = 1; $i <= $count_dirs; $i++) {
    
    $current_folder = scandir($dirs[$i-1]);
    $current_folder = array_diff($current_folder, $exclude);
    $count_files = count($current_folder);
    
    if($count_files >= $max_files and $count_dirs <= $i) {
        mkdir('images'.$i);
		$uploaded_dir = 'images'.$i.'/';
    } else if($count_files < $max_files) {
		$uploaded_dir = 'images'.--$i.'/';
		break;
	} else {
		$ii = $i-1;
		$uploaded_dir = 'images'.$ii.'/';
	}

}

?>
 
Явно съм бил тръгнал по грешния път. Функцията glob();, даже не я бях чувал..

Мерси за изчерпателното обяснение и за кода, които ми написа.

Тествах и работи, сега остава да настроя останалите неща /самото качване на снимките/. Още веднъж благодаря. :?:
 

Горе