Проблема большой фотогалереи возникла на корпоративном портале от 1С-Битрикс. За более чем год использования ограничения на максимальный размер файла размер папки /upload/ содержащей все загруженные файлы стал более 20 GB.
Особенностью данной задачи служило, то что заранее неизвестны пути к изображениям фотогалереи. Ниже приведено решение, которое будет работать на всех проектах вне зависимости от системы управления контентом.
Скрипт делает следующее:
1) Рекурсивно обходит все файлы в директории из которой запущен;
2) Если файл имеет расширение gif, png или jpeg, размер более 500 Kb, высоту более 850px и ширину более 640 px сжимает его пропорционально до этих параметров.
Требования:
1) На сервере должна быть установлена библиотека gd для php.
2) Если файлов много, сжатие займет значительное время, поэтому придется запускать из консоли, следовательно потребуется ssh.
3) У скрипта должно быть право на изменение изображений.
Скрипт с комментариями приведен ниже:
[sourcecode lang="php"]
#!/usr/local/bin/php
#!/usr/local/bin/php
// settings
global $result_width, $result_height, $max_size, $resized_files;
$result_width=850; // ширина изображения
$result_height=640; // высота изображения
$max_size=500000; // минимальный размер
//settings
function img_resize($src, $out, $width, $height, $color = 0xFFFFFF, $quality = 100)
{
global $result_width, $result_height, $max_size, $resized_files;
if ((strpos(strtolower($src), '.jpg')!==false)||(strpos(strtolower($src), '.gif')!==false)||(strpos(strtolower($src), '.png')!==false)){
// Если файл не существует
if (!file_exists($src)) {
return false;
}
// Получаем массив с информацией о размере и формате картинки (mime)
$size = getimagesize($src);
// Исходя из формата (mime) картинки, узнаем с каким форматом имеем дело
$format = strtolower(substr($size['mime'], strpos($size['mime'], '/') + 1));
//и какую функцию использовать для ее создания
$picfunc = 'imagecreatefrom'.$format;
if (($size>$max_size)&&($size[0]<$width)&&($size[1]>height)){
$resized_files++;
// Вычилсить горизонтальное соотношение
$gor = $width / $size[0];
// Вертикальное соотношение
$ver = $height / $size[1];
// Если не задана высота, вычислить изходя из ширины, пропорционально
if ($height == 0) {
$ver = $gor;
$height = $ver * $size[1];
}
// Так же если не задана ширина
elseif ($width == 0) {
$gor = $ver;
$width = $gor * $size[0];
}
// Формируем размер изображения
$ratio = min($gor, $ver);
// Нужно ли пропорциональное преобразование
if ($gor == $ratio)
$use_gor = true;
else
$use_gor = false;
$new_width = $use_gor ? $width : floor($size[0] * $ratio);
$new_height = !$use_gor ? $height : floor($size[1] * $ratio);
$new_left = $use_gor ? 0 : floor(($width - $new_width) / 2);
$new_top = !$use_gor ? 0 : floor(($height - $new_height) / 2);
$picsrc = $picfunc($src);
// Создание изображения в памяти
$picout = imagecreatetruecolor($width, $height);
// Заполнение цветом
imagefill($picout, 0, 0, $color);
// Нанесение старого на новое
imagecopyresampled($picout, $picsrc, $new_left, $new_top, 0, 0, $new_width, $new_height, $size[0], $size[1]);
// Создание файла изображения
imagejpeg($picout, $out, $quality);
// Очистка памяти
imagedestroy($picsrc);
imagedestroy($picout);
return true;
} else {
return false;
}
} else {
return false;
}
}
function scan_dir($dirname)
{
// Объявляем переменные замены глобальными
global $count_files;
global $result_width, $result_height, $max_size, $resized_files;
// Открываем текущую директорию
$dir = opendir($dirname);
// Читаем в цикле директорию
while (($file = readdir($dir)) !== false)
{
// Если файл обрабатываем его содержимое
if($file != '.' && $file != '..')
{
// Если имеем дело с файлом - производим в нём замену
if(is_file($dirname.'/'.$file))
{
$str = $_SERVER['DOCUMENT_ROOT'].$_SERVER["REQUEST_URI"].$dirname."/".$file;
$str = str_replace("//", "/", $str);
$str = str_replace("./", "", $str);
$str = str_replace("//", "/", $str);
echo("Try to resize file # ".$count_files." \n ");
img_resize($str, $str, $result_width, $result_height);
// echo($_SERVER["DOCUMENT_ROOT"].$_SERVER["REQUEST_URI"].$dirname."");
$count_files++;
}
// Если перед нами директория, вызываем рекурсивно
// функцию scan_dir
if(is_dir($dirname."/".$file))
{
scan_dir($dirname."/".$file);
}
}
}
// Закрываем директорию
closedir($dir);
}
$time1 = time();
$dirname = "./"; // Текущая директория
scan_dir($dirname); // Вызов рекурсивной функции
echo "All files: $count_files \n ";
echo "Resized files: $resized_files \n ";
$time2 = time();
echo("Total time:".($time2-$time1)." sec \n");
?>
[/sourcecode]
Результат работы оказался таким: скрипт работал чуть более 4х часов, изменил чуть более
20 000 изображений. Размер папки /upload/ стал 5 Gb, т.е. уменьшился в 4 раза!
Скачать скрипт можно здесь.