Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Форма для загрузки файла по ссылке (https://javascript.ru/forum/misc/72601-forma-dlya-zagruzki-fajjla-po-ssylke.html)

laimas 15.02.2018 20:47

Цитата:

Сообщение от kupidon
Вообще проверку убрать?

isset($_POST) - это просто глупо, ибо всегда будет true, даже если этот массив пуст. А вот если ссылки на сетевые файлы передаются под именем file, то isset($_POST['file']) определит есть ли такое, но не определяется пусты ли они.

Вы же добавленному товару добавляете фото, а значит обязательным должна быть проверка наличия поля с ID товара, и не просто наличие, а возвращает число и запрос по этому id в базу возвращает истину, то есть:

if($id = (int)$_POST['id'] AND query('SELECT 1 FROM table WHERE id='.$id)) {
     //это товар - загрузка
}


При отключенных нотайсах достаточно, и isset(...) не обязателен. А с $_SERVER["REQUEST_METHOD"] == "POST", то при запросе к скрипту выполняющему исключительно задачу загрузки, лучше в самом его начале прописать:

if($_SERVER["REQUEST_METHOD"] == "GET") exit;


О $_FILES['file']['name'] забыть, оно вам не нужно, это товары а не галерея в Instagram.

laimas 15.02.2018 20:56

Цитата:

Сообщение от kupidon
$file_name = basename('https://www.google.ru/images/srpr/logo11w.png');

Какие basename, зачем? Именуйте файлы генерируя их имена как хеш UID.
Цитата:

Сообщение от kupidon
И как из этого примера потом получить ссылку на временный файл?

Нет тут никакого временного файла - файл загрузить в переменную сначала надо и это будет в памяти. Затем проверить по всем условиям этот файл - картинка ли и т.д. Затем отдать в функцию на обработку (если это есть, читайте выше), эта функция его и сохранит. Никаких file_put_contents.

kupidon 16.02.2018 12:09

Цитата:

Сообщение от laimas
файл загрузить в переменную сначала надо и это будет в памяти.

:cray: Я не знаю как его загрузить

kupidon 16.02.2018 12:24

Нашел вот такой код:
<?php
  $link = "http://myrusakov.ru/images/site.jpg";
  $file = file_get_contents($link);
  file_put_contents("site.jpg", $file);
?>


ссылку на внешний файл я смогу получить в обработчике. смогу ли я таким способом закачать файл в свою временную папку?

laimas 16.02.2018 13:38

Цитата:

Сообщение от kupidon
Я не знаю как его загрузить

У вас не только с этим проблемы. Мне некогда, поэтому общие положения.

Форма содержит поле для ввода сетевого пути к файлу. Этих полей может быть много. Как клонировать и добавить поле в форму на форуме уже не раз писалось, найти. Пусть это поле имеет имя file[].

Также формой передается id товара, а при необходимости и его родителя.

Загрузка локальных файлов осуществляется полем тоже с именем file[].

Загрузку файлов можно начитать только если id товара действительно, а если и родитель, то и он. Это условие описано ранее. Далее могут быть два сценария:
1) последовательная загрузка: сначала локальные файлы если есть с полной обработкой, затем сетевые при их наличии с полной обработкой
2) комбинированная: создается массив ссылок на временные файлы, затем проходом в цикле они отдаются в полную обработку.

Сервер имеет функцию производящую основные операции с изображениями. Если функция возвращает 0, значит ошибок при обработке не возникало. В противном случае, это код ошибки.

$mime = ['image/png', 'image/jpeg']; //разрешенные типы
$size = 1000000; //макс. размер.

function processingIMG($f) {
    if(!$im = @imagecreatefromstring($f)) return 1; //файл не является изображением
    //далее операции
    //сохранение
    return 0; 
}


В случае первого сценария проверяются файлы массива $_FILES на отсутствие ошибок при загрузке, загружен ли файл по HTTP, предварительно на тип, и на допустимый размер. Проверка на размер очень важна, о ней ниже. Если Эти условия соблюдены временный файл отдается processingIMG(file_get_contents($_FILES['file']['tmp_name'][$i])).

Затем обрабатываются файлы сетевые если они есть, и это тоже массив файлов.

if($url = array_diff(filter_var_array($_POST['file'], FILTER_VALIDATE_URL), [false])) {
    foreach($url as $a) {
        $hdr = get_headers($a, 1);
        if(strpos($hdr[0], '200')) {
            if(in_array($hdr['Content-Type'], $mime) && $hdr['Content-Length'] <= $size) $upl[] = $a;    
        }
    }
    
    foreach($upl as $url) {
        if($f = @file_get_contents($url)) {
            if(processingIMG($f)) echo 'Error';    
        }
    }
}


Из полученного массива ссылок сетевых файлов будут удалены те, что имеют некорректный сетевой путь. Прежде чем реально загружать сетевые файлы, сначала получается информация о них, посредством запроса заголовков. После анализа заголовков из массива списка сетевых файлов будут удалены те, у которых заголовок не вернул статус 200, и у которых тип не является разрешенным и размер больше разрешенного. При этом надо учесть, что изображение может отдаваться не по прямой ссылке, а скриптом, но в заголовке будет не тип изображения, и он будет исключен из набора. Кроме этого url не обязательно прямой путь, возможны перенаправления, количество которых должно быть определено, если разрешено, и проанализировано (рассказывать не буду, запускайте get_headers на примерах, смотрите результаты, анализируйте, думайте, действуйте).

Полученный массив валидных ссылок обходится циклом, где производится загрузка файлов посредством file_get_contents($url) и загруженный файл отдается также на дальнейшую обработку в processingIMG().

Если так хочется получить список временных файлов, которые потом одним циклом обработать, то сетевые файлы нужно сначала загрузить, каждый в созданный временный файл, получая путь к нему. Пути заносить в массив, который соединить с массивом путей временных файлов загруженных по HTTP, и полученный массив обойти циклом.

Но есть некоторые проблемы связанные с tmpfile(), о которых можно почитать тут, и заодно воспользоваться решением предложенным, если для вас это так принципиально.

О проверке на размер. Если файл будет обрабатываться графической библиотекой (GD и прочее), то нужно учитывать следующее. Если эта загрузка для себя и вы не враг себе, а также гарантируете, что ваш вход надежно защищен, то терпимо. Но если закинуть на сервер изображение 10000х10000, которое в формате JPEG может быть сжато и до смешного размера, то проверку на размер файла оно пройдет. Но для работы с этим файлов в GD под ресурс потребуется памяти 10000х10000Х32 = 3 200 000 000 байт (GD не будет спрашивать вас нужен ли вам альфа канал, он все равно под него отведет один байт). И у вас будут возникать фатальные ошибки.

Поэтому до открытия ресурса нужно узнать разрешение файла (getimagesize) и примерно посчитать память требуемую (полученную умножать на два, при операциях могут создаваться два ресурса), хватит ли ее.

laimas 16.02.2018 13:39

Цитата:

Сообщение от kupidon
Нашел вот такой код

Не собирайте мусора, думайте. ;)

laimas 16.02.2018 13:42

Цитата:

Сообщение от kupidon
смогу ли я таким способом закачать файл в свою временную папку?

Либо забудьте об этом термине в контексте сетевых файлов, либо читайте то, что по ссылке.

Для того чтобы загрузить обработать сетевой файл никакой временной папки в общем то и не нужно, как не обязательно файлы загруженных формой перемещать из временного каталога в какой либо, только для того, чтобы их обработать.

kupidon 16.02.2018 14:58

Спасибо большое за столь огромный ответ. Сегодня буду его переваривать. Обязательно отпишусь о результате, надеюсь он все-таки будет.

kupidon 16.02.2018 15:06

Цитата:

Сообщение от laimas
Сообщение от kupidon
смогу ли я таким способом закачать файл в свою временную папку?

Либо забудьте об этом термине в контексте сетевых файлов, либо читайте то, что по ссылке.

Хочу добавит к вышенаписанному. Вы почти в каждом сообщении мне делаете акцент на проверку ид товара. Я же хочу обратить внимание, что я сделал загрузку и вывод из локальных файлов. Все отлично работает. Я для этого использовал и ид товара и проверку преобразование размера и генерирование уникального имени. То есть это у меня уже есть. Также я загружаю фото из карточки УЖЕ созданного товара, а следовательно не надо проверять есть он в БД или нет. Он есть 100%. Размер и формат - согласен.
Что касается временной папки, то она мне нужна в любом случае. В нее я загружаю временный файл, а уже оттуда манипулирую обработкой изображения, потом сам удаляю оттуда его.
Я понимаю что уровень ваших знаний вразы больше моего и у вас есть куча оптимальных вариантов и ответов на мой вопрос, но на данном этапе мне хочется проще. Я сам порою открывая свои творения 2-х годичной давности посмеиваюсь. Понимаю что и вам такого, но увы , учимся на ошибках ))

laimas 16.02.2018 15:16

Цитата:

Сообщение от kupidon
Также я загружаю фото из карточки УЖЕ созданного товара, а следовательно не надо проверять есть он в БД или нет.

Это как? :)
Цитата:

Сообщение от kupidon
Что касается временной папки, то она мне нужна в любом случае. В нее я загружаю временный файл, а уже оттуда манипулирую обработкой изображения, потом сам удаляю оттуда его.

Зачем? У вас лично ее вообще не должно быть, временная папка определяется настройками сервера и забота очищать ее от мусора возложена на сборщика мусора. Именно в эту временную папку, а не вашу, загружаются файлы от формы. Ваша задача их обработать, удаляться они из папки и без вашего участия.

А вот куда-то закачивать сетевые файлы, потом их брать от туда для обработки, это вообще глупо, ибо file_get_contents уже вам возвращает файл - обработайте его и уже результат обработки помещайте на хранение.

Что касается id и прочего, это для последовательности указано, есть и хорошо.

Цитата:

Сообщение от kupidon
но на данном этапе мне хочется проще.

А что я такого сложно написал? Главное в написанном, это не грузить на сервер мусор, чего вы своей простотой и делаете, и это очень плохо.

Nexus 16.02.2018 15:37

Цитата:

Сообщение от kupidon
Также я загружаю фото из карточки УЖЕ созданного товара, а следовательно не надо проверять есть он в БД или нет. Он есть 100%.

Загрузка изображений со страницы редактирования товара отнюдь не говорит о том, что товар абсолютно точно существует.
Всякое бывает, к примеру: 2 пользователя зашли в админку единовременно, первый пошел фоточки товару заливать, второй в это время его (товар) по какой-то причине удалил.

laimas 16.02.2018 15:42

Nexus,
главное, забывают о том, что загружать могут и левое. )

Nexus 16.02.2018 15:46

laimas, при разработке доверять вообще ничему нельзя, тем более внешним данным )

laimas 16.02.2018 15:51

Цитата:

Сообщение от Nexus
при разработке доверять вообще ничему нельзя, тем более внешним данным

Вот этого к сожалению и не понимают.

kupidon 17.02.2018 19:46

Вчера победил загрузку и файлы начались сохраняться ко мне на сервак.
Но сделал немного по другому, не как вы мне предлагали..
И все же, чтобы подвести итог нашей дискуссии, заккомментировал пока мой рабочий код, поскольку уважаю ваши советы и
хочу попробовать сделать с вашим кодом. НО поскольку для меня это темный лес, и все функции для меня новые.
Итак, вот что я вставил в обработчик:
if (!empty($_POST['file_url'])){
	$mime = array('image/png', 'image/jpeg'); //переделал строку с вашим кодом, а то он ругался на кв ковычки
	$size = 1000000; //макс. размер.

	function processingIMG($f) {
	    if(!$im = @imagecreatefromstring($f)) return 1; //файл не является изображением
	    //далее операции
	    //сохранение
	    return 0; 
	}

	if($url = array_diff(filter_var_array($_POST['file_url'], FILTER_VALIDATE_URL), [false]))   	{
	    foreach($url as $a) {
	        $hdr = get_headers($a, 1);
	        if(strpos($hdr[0], '200')) {
	            if(in_array($hdr['Content-Type'], $mime) && $hdr['Content-Length'] <= $size) 				$upl[] = $a;    
	        }
	    }
    
    	foreach($upl as $url) {
        	if($f = @file_get_contents($url)) {
            	if(processingIMG($f)) echo 'Error';    
        	}
    	}
	}
}


Вот что приходит в ответ:
Выдает ошибку.
<!--error--><br />
<b>Parse error</b>: syntax error, unexpected '[' in <b>adm\include\upload_photo\ajax_upload.php</b> on line <b>97</b><br />
<script language=JavaScript src='/denwer/errors/phperror_js.php'></script>

97 строка это:
if($url = array_diff(filter_var_array($_POST['file_url'], FILTER_VALIDATE_URL), [false]))


Эти функции для меня новые и без совета мне не обойтись

Nexus 17.02.2018 20:28

kupidon, "[false]" замените на "array(false)".
У вас, вероятно, версия php меньше 5.4 поэтому при объявлении массива через квадратные скобки сыпятся ошибки.

Upd. У вас $_POST['file_url'] - массив?

kupidon 17.02.2018 20:36

Да, у меня денвер. Тестирую на компе.

<!--error--><br />
<b>Warning</b>: filter_var_array() expects parameter 1 to be array, string given in <b>Z:\home\19sp.ru\www\forum\mysp\adm\include\uplo ad_photo\ajax_upload.php</b> on line <b>156</b><br />
<script language=JavaScript src='/denwer/errors/phperror_js.php'></script><!--error--><br />
<b>Warning</b>: array_diff() [<a href='function.array-diff'>function.array-diff</a>]: Argument #1 is not an array in <b>Z:\home\19sp.ru\www\forum\mysp\adm\include\uplo ad_photo\ajax_upload.php</b> on line <b>156</b><br />
<script language=JavaScript src='/denwer/errors/phperror_js.php'></script>

В этой же строке:
if($url = array_diff(filter_var_array($_POST['file_url'], FILTER_VALIDATE_URL), array(false)))

kupidon 17.02.2018 20:37

Цитата:

Сообщение от Nexus
Upd. У вас $_POST['file_url'] - массив?

нет , это одиночная ссылка

Nexus 17.02.2018 20:41

kupidon, вы если английский не знаете, то переведите текст ошибки с помощью какого-нибудь переводчика, это значительно упростит дебаг.
Текст ошибки - не какое-либо заклинание, а вполне ясное описание возникшей ошибки.

Функция "filter_var_array" принимает в ка-че первого аргумента массив, вы передали строку, отсюда и ошибка.
Оберните $_POST['file_url'] в массив, либо воспользуйтесь функцией "filter_var".

Цитата:

Сообщение от kupidon
Да, у меня денвер. Тестирую на компе.

У меня тоже стоит денвер, но версия 7.1 ;)

kupidon 17.02.2018 21:05

Спасибо Вам. Обернул в массив, заработало.

Файл на стороннем сервере я проанализировал. Если условия удовлетворены (размеры и тип), теперь сохраняю его в СВОЮ временную папку, для обработки.

У меня есть два варианта сохранения:
1. С помощью fopen и fwrite
if (file_get_contents($_POST['file_url']))
{
	$content = file_get_contents($_POST['file_url']);
	$f = fopen( "../../../photos/temp/temp.jpg", "w" );
	if (fwrite( $f, $content ) === FALSE)
	{
		echo "Не могу произвести запись в файл.";
		exit;
	}
	else {
		$filesize = filesize_get($file); 
		echo " Файл <font color='red'>" .$file ."</font> записан.".$filesize;
		fclose( $f );
	}
}
else echo "Не могу качать файл.";


2.
$file = 'https://www.google.ru/images/srpr/logo11w.png';
$file_name = basename('https://www.google.ru/images/srpr/logo11w.png');
file_put_contents('my_folder'.$file_name, file_get_contents($file));



какой мне выбрать?

Nexus 17.02.2018 21:37

kupidon,
$file = 'https://www.google.ru/images/srpr/logo11w.png';
// Добавляю хэш к имени файла
$file_name = md5(microtime(true).rand(0,999999)).'_'.basename('https://www.google.ru/images/srpr/logo11w.png');
$file=file_get_contents($file);
$file_path='my_folder'.$file_name;
if(empty($file))
	throw new \Exception('Could not read remote file');
	
if(file_put_contents($file_path,$file)<=0)
	throw new \Exception('Could not save remote file');

// я бы проверял не заголовки ответа удаленного сервера на запроса изображения, 
// а сам полученный файл, на то является ли он изображением или нет

laimas 17.02.2018 22:47

Цитата:

Сообщение от kupidon
/denwer/errors/phperror_js.php

Денвер в утиль, он давно умер, скачивайте Open Serever. Это такой же компактный не требующий инсталляции и работающий с чего угодно как и Денвер локальный сервер, но с гораздо большими возможностями и более удобный. Проект живой и постоянно обновляется как по мере выхода новых версий компонентов, так и в плане новых возможностей.

Цитата:

Сообщение от kupidon
$mime = array('image/png', 'image/jpeg'); //переделал строку с вашим кодом, а то он ругался на кв ковычки

Квадратных кавычек нет. :) Ругается потому, что вы используете версию РНР ниже 5.4, в которых нельзя объявить массив литерально [], а только как array(). Вы должны использовать ту версию языка, которая доступна на реальном сервере. И если доступны версии 5.4 и выше, то ориентируйтесь на них, в них больше возможностей, что позволяет писать код более компактным, ну и конечно же, это устранение "болезней" предыдущих версий.

Поэтому если я далее пишу код, то ориентируюсь на версию не ниже 5.5, учитывайте это.

Цитата:

Сообщение от kupidon
НО поскольку для меня это темный лес, и все функции для меня новые.

Это не страшно, достаточно заглянуть в руководство по языку (это должно быть настольной книгой, библией на ночь, которую можно скачать на официальном сайте в формате CHM), и в темном лесе появятся проблески света. ;)

Сказанное выше, это рекомендации, и это я советую сделать. А то, что далее написано, это вы должны делать и не потому, что я советую, а вы уважаете. Все что ниже, вы обязаны делать исходя из требований к безопасности кода.

**********

Возможно и много писанины получится, пока есть время написать можно (чем дольше читать будут и переваривать, тем больше у меня времени будет :) ). Повествование в томах, дабы не напороться на ограничения.

Война и мир. Ремейк. Том 62

Ужастики

Также я загружаю фото из карточки УЖЕ созданного товара, а следовательно не надо проверять есть он в БД или нет. Он есть 100%.

Второе предложение можно принять за постулат, а вот первое будет постулатом только пока выборка из базы живет на сервере. Как только результат выборки отдали клиенту, можно смело сказать, что она уже не принадлежит базе потому, что нет такой же 100-процентной гарантии, что она вернется на сервер в том же виде.

Существует опасный вид атаки называемый "человек посередине" (Man in the middle, MITM), которой подвержены и безопасные соединения, а обычный http тем более. Вы отдали клиенту "У нас все замечательно!", а клиент может получить "Кошка сдохла." и вернет вам "Примите наши соболезнования." Кроме этого в сети шарятся кучи ботов сканирующие страницы с формами и отсылающие их копии серверу жертве.

Если не учитывать всех "сетевых насекомых", принимать на веру как есть, то такая вера может закончится большим разочарованием. Например, в вашем случае в таблице описывающей файлы товаров появятся "бесхозные" записи, а в каталог будут залиты бесполезные картинки.

Дихлофос

Защита, это вопрос серьезный, широкий, понимание и знания будут накапливаться, нужно только обязательно интересоваться этими вопросами. Но уже в самом начале практики написания кода нужно выполнять элементарные действия:

- сервер отдавая данные клиенту не должен допустить на нем XSS атаки, пропуская вывод данных полученных извне через htmlspecialchars()
- не использовать в именах полей формы имена SQL таблиц, а если используются, то только их часть после префикса
- данные поступающие на сервер извне подлежат обязательной проверке/фильтрации
- блокировать вывод ошибок и предупреждений на страницах на удаленном сервере

Как пример, а не обязательное требование использовать.

Надежный пароль 123456789, это уже анекдот, но тем не менее такое есть и не в единственном случае. Сюда же можно отнести и именование полей форм: name, first_name, last_name, phone, email, login, password, ... или вариации этого. Боты такие формы любят, что и для чего ясно, и китайца "арендовать" не нужно для снятия слепка с формы.

Как можно продихлофосить. Например, все имена формы содержат первичный ключ, который есть хеш случайного значения, который формируется сервером и запоминается на нем. Вторичные ключи, это индексы реальных имен, которые могут быть связаны и с именами полей SQL таблицы, и прочими другими данными, и которые знает только сервер. То есть имена полей будут выглядеть так:

name="4a0d42e025eb49edf7f292be67c1099f[5]"
name="4a0d42e025eb49edf7f292be67c1099f[1]"
name="4a0d42e025eb49edf7f292be67c1099f[3]"
....
name="4a0d42e025eb49edf7f292be67c1099f[9]"

При каждом запросе формы первичный ключ меняется. Ключ живет только на время сессии, а также удаляется после приема формы. То есть, нельзя будет отправить вторично эту форму, север ее просто не примет, так как ключа ее на сервере не будет.

Использование иконок для полей вместо текстовых меток, формирование формы клиентским сценарием еще более осложняет жизнь боту.

Рекогносцировка

Хорошим тоном является оповещение клиента о предпочтениях сервера - чего он хочет получить от клиента. А проверка ввода в поля формы соответствию ожидаемому не являясь средством защиты для сервера и служащая для предотвращения случайных ошибок пользователя, тем не менее дает серверу карт-бланш. Сервер зная о том, что клиент им информирован по всем полям, клиент имеет предоставленный ему сервис предотвращающий ошибки, обнаружив первое же несоответствие в полученных данных может законно завершить работу, не разбираясь далее.

В современном HTML информирование и проверку можно возложить на браузер без всяких затрат на написание кода. Но в форме загружающей файлы для таких полей нативной проверки нет. Более того, если сервер не сообщит клиенту параметров по загрузке, то и пенять не на кого. Клиент должен быть извещен о типах файлов, которые примет сервер. Эти типы нужно перечислить в атрибуте accept поля file. Умные браузеры в диалоге выбора файлов будут отображать файлы только указанных типов. Клиенту также передается максимальный размер файла, который можно загрузить, общее количество файлов для загрузки за один раз, и максимальный размер данных, который можно передать методом POST. Эти данные сервер должен получить из настроек сервера, передав их клиенту.

Если файлы, это графика и предполагается ее обработка на сервере, то клиенту должно быть передан размер памяти доступный под такую обработку.

При выборе файлов, клиентский сценарий должен проверять выбранное на соответствие типу, размеру, количеству и соответствие общего размера выбранного разрешенному для загрузки. А если предполагается работа с графикой, то получать разрешение выбранных файлов, рассчитывать объем памяти под них требуемый, чтобы он не был больше допустимого сервером. Либо просчитав возможности сервера, не разрешать к загрузке графику выше определенного разрешения.

********

Если эти замечания вам известны, а тем более выполняются в ваших формах, это хорошо, то, что зря я по клавишам стучал, не страшно. Но если из этого что-то упущено или не сделано из-за принципа "нужно проще", то смысла в терзаниях "как написать код загружающий файл" нет, так как то, что выше, это обязательная преамбула к коду.

laimas 17.02.2018 23:47

Том 63

Бастион

Сервер обязан проверять данные соответствию ожидаемых. Вы не разобрались с кодом, который я писал, а вам еще и советуют разное, и вы путаясь делаете то, что не следует.

Вы получаете ссылки на сетевые файлы, но не видно чтобы вы учитывали возможные случайные ошибки пользователя, и самые частые, это лишние пробелы по краям. Либо вы проверяя каждое значение формы в цикле (во время фильтрации), удаляете их, любо удалите их сразу у всех значений массива, если над данными производятся групповые операции:

if($_POST) {
    array_walk_recursive($_POST, function(&$v) {
        $v = trim(stripslashes($v));
    });
}


В вашем коде вы допускаете опасные ошибки. Не проверив наличие файла по сетевому пути (проверять его наличие загрузкой по факту, это расточительно), используя имя файла источника, опять таки не проверив что это за файл, загружаете его в каталог:

$file_name = basename('https://www.google.ru/images/srpr/logo11w.png');
file_put_contents('my_folder'.$file_name, file_get_contents($file));

Это предпосылка к тому, что на ваш сервер через эту дыру зальют исполняемый файл. Если каталог не защищен от запуска в нем исполняемых файлов, то его сразу же и запустят, и ...

Если, допустим, будут разрешены переходы при получении сетевых файлов, то придется анализировать заголовок Location, а к примеру я его могу и как location написать. В общем ранее написанный код лучше немного дополнить

//с учетом, что возможные крайние пробелы удалены в данных
if($url = //массив ссылок на сетевые файлы не пуст, empty тут как козе баян
    array_diff( //удалить из массива
        filter_var_array( //проверить массив данных
            $_POST['file'], 
            FILTER_VALIDATE_URL //фильтом проверки URL
        ), 
        [false]) //элементы не прошедшие фильтрацию
    ) {
    
    foreach($url as $a) {  
        $hdr = array_change_key_case(get_headers($a, 1)); //запросить информацию о файле, вернув заголовки как ключи в нижнем регистре 
        if(strpos($hdr[0], '200')) { //файл существует
            if(in_array($hdr['content-type'], $mime) && $hdr['content-length'] <= $size) $upl[] = $a; //если разрешенный тип и размер, добавить в загрузку  
        }
    }
     
    foreach($upl as $url) { //есть сетевые файлы для загрузки 
        if($f = @file_get_contents($url)) { //считываем файл
            //никаких сохранений в каталог
            //если использовать getimagesize для проверки разрешения, то только во временный файл
            //но можно получить ширину/высоту и без этого, просто распаковав эти данные из заголовка файла  
            //если тип, объем памяти Ок, отдаем на обработку
            if(processingIMG($f)) echo 'Error';   
        }
    }
}

function processingIMG($f, $name) {
    $end = 0;
    //то что предыдущие проверки типа возвращают ОК, еще не значит, что файл есть графика
    //здесь открывается GD ресурс из строки
    //если файл не графика, значит ресурс не будет создан  
    if(!$im = @imagecreatefromstring($f)) {
        $end = 1; //файл не является изображением
        goto out;
    }
    //далее операции над файлом
    //сохранение, под сгенерированным именем, по указанному пути, с одним типом, чай не галерея искусств
    //с определенным установками качеством через константу QUALITY
    imagejpeg($im, $name, QUALITY);
    out:
    @imagedestroy($im);
    return $end;
}

laimas 18.02.2018 01:27

Том 64

После битвы

Можете представить, что вы беседуете с роботом "за жизнь"? Нет, беседовать можно, конечно, но вот вряд ли он вас поймет. Аналогично - сервер зная, что клиент оповещен, а значит, если в пришедшем ошибки, которые явно есть результат обхода проверки ввода или вообще роботом прислано, нужно ли серверу вести с роботом диалог?

Если предполагается диалог клиент сервер, в случае, если на клиенте нет проверки ввода, тогда да, возвращаем клиенту ошибки. Иначе exit, сообщение "Could not read remote file" роботу как мертвому припарка, а желающему вас прощупать не стоит сообщать подробностей. А на локальном сервере, в режиме отладки, нужно выводить даже предупреждения, безобидность, на первый взгляд, некоторых, может быть причиной уже ошибок далее в коде. Режим отладки можно включать и на удаленном сервере если пользователь имеет права "видеть их". Возникают и на удаленном сервере ошибки, причиной которых могут быть конфигурации или иные особенности сервера, которые на локальном сервере не отследить.

Процессы над графикой могут порождать ошибки, хотя если заранее определено разрешение изображения и рассчитан размер памяти под него, и размер не выше допустимого, то может возникнуть только одна ошибка - не создан ресурс, то есть, файл не является изображением.

Все бы ничего, если бы такая ошибка возникала на первом загружаемом файле. Но если первый был корректный, а второй явная подстава, просто завершить работу означает, что в каталоге будет сохранен мусор.

Если же обработанные файлы сохранять в сессию под именами сгенерированными, как ключами, то и в функции processingIMG() можно завершать работу скрипта. Сохраненные до ошибки файлы будут удалены сборщиком мусора. Если же ошибок не возникло, то файлы из сессии переносятся в каталог, а ключи (имена файлов) одним запросом записываются в базу.

Каждый тип графического файла имеет заголовок, из которого можно узнать информацию о файле, включая его ширину и высоту. Считав по известному смещению данные о разрешении, можно их узнать функцией unpack(). Это позволит не сохранять на диск файл ради получения этой информации. Это на будущее как прикладная задача для изучения в общем полезных функций pack() и unpack().

Даже при соблюдении всех предосторожностей, тотальной проверки, каталог в который загружаются файлы извне и являющийся публичным, должен иметь соответствующие права. Права на запись в этот каталог получает владелец только на время записи в него файла, а после записи возвращает прежние. В каталоге должен быть запрещен запуск исполняемых файлов посредством .htaccess

#запретить листинг файлов каталога
Options -Indexes
#запретить выполнение скриптов в каталоге
php_flag engine 0
AddType "text/plain" .php .cgi .pl .fcgi .fpl .phtml .shtml .php2 .php3 .php4 .php5 .php6 .php7 .asp .jsp

kupidon 18.02.2018 18:23

Цитата:

Сообщение от laimas
Возможно и много писанины получится, пока есть время написать можно (чем дольше читать будут и переваривать, тем больше у меня времени будет )

Это точно...

Спасибо Вам за такие развернутые ответы. Мне нужно время, чтобы все осознать. Про то, чтобы сделать просто, но с дырявым кодом я теперь понял..Многое придется перекроить теперь. Буду отписываться по мере работы.


Часовой пояс GMT +3, время: 04:02.